Skip to content

feat(scripting): add zod schemas and viem transform helpers#690

Merged
yahgwai merged 52 commits intomainfrom
feat/zod-schema
Apr 22, 2026
Merged

feat(scripting): add zod schemas and viem transform helpers#690
yahgwai merged 52 commits intomainfrom
feat/zod-schema

Conversation

@yahgwai
Copy link
Copy Markdown
Contributor

@yahgwai yahgwai commented Apr 8, 2026

Summary

Adds zod schemas and transforms for every SDK function that takes RPC/client input. Schemas validate JSON input and transforms convert it to SDK-ready arguments -- RPC URLs become viem clients, private keys become accounts, strings become bigints. The target audience here is devs who are already familiar with zod, and helping them to write scripts without messing up the arg parsing, and letting them follow a opinionated structure. Devs who arent familiar with zod dont get benefit here, but it's not a complicated library to learn, and I think it's a useful thing to know about.

WARNING: we're creating schemas for every function, so there's a lot of code being added here, but two things are worth focusing on which help us to gain confidence in the correctness of the code:

  • The schema type tests - here we're trying to test that the output of the transformed schema could be directly into its equivalent sdk function, so if you're confident those tests work then in theory the schemas are good from a correctness point of view
  • In all cases where we can we set the return type of the schema transform to Parameters

Not included for now

  • Additional parsing libs. Now that we have zod schemas which will parse json, we can use existing tooling to convert yaml, env vars or cli args to json and than parse with the same schema giving scripts more options of what they expose to users.
  • Describe() - we can add documentation to the schemas to give consumers and idea of what values to put into the params. Those descriptions can be accessed via a dry-run/help command or zod can be converted into json schemas to directly expose the documentation.
  • Documentation and readme. Three sets of documentation is required: one for sdk maintainers, one for script writers and one for users of the cli.
  • Extending the CLI with some standard useful scripts to be used by SRE/other consumers

yahgwai added 26 commits March 19, 2026 13:20
Prepare token bridge deployment transactions without requiring an orbit
chain RPC. enqueueTokenBridgeDeployment encodes the createTokenBridge
call with caller-provided gas params. enqueueSetWethGateway encodes the
setGateways call through UpgradeExecutor with explicit retryable costs.
- Rename maxFeePerGas to maxGasPrice in enqueueSetWethGateway for
  consistency with enqueueTokenBridgeDeployment and the constant name
- Nest rollup/rollupOwner in params object to match existing
  createTokenBridgePrepareTransactionRequest pattern
- Update idempotency comment to explain parent-chain-only check rationale
  and that failed retryables should be manually redeemed
- Restore gas override comments from reference implementation
- Replace duplicate deposit test with calldata verification test for
  enqueueSetWethGateway
…red ABI

- Rename enqueueTokenBridgeDeployment to
  enqueueTokenBridgePrepareTransactionRequest
- Rename enqueueSetWethGateway to
  enqueueSetWethGatewayPrepareTransactionRequest
- Extract parentChainGatewayRouterAbi to src/contracts/GatewayRouter.ts,
  replacing inline copies in both enqueue and existing set weth gateway files
…tion

- Split maxSubmissionFee into maxSubmissionCostForFactory and
  maxSubmissionCostForContracts to match existing retryable fee formula
- Update retryable fee calculation to sum both submission costs
- Rename enqueueSetWethGateway* to enqueueTokenBridgePrepareSetWethGateway*
  to match createTokenBridgePrepareSetWethGateway* naming convention
- Remove CR comments
Fixes vitest type checker failure caused by dynamic import syntax.
Extract getFactoryDeploymentDataSize and getContractsDeploymentData from
the existing estimation functions so that the enqueue variants can reuse
the same data-size logic for calculating retryable submission fees.
Replicates the SDK's estimateSubmissionFee logic: calls the Inbox's
calculateRetryableSubmissionFee on the parent chain with the current
base fee, then applies a 300% safety buffer matching the SDK default.
…tions

The enqueue functions now estimate maxSubmissionCost from parent chain
state using the shared data-size helpers and the Inbox's
calculateRetryableSubmissionFee, matching the approach used by the
create* variants via the SDK. Callers no longer need to provide
maxSubmissionCostForFactory, maxSubmissionCostForContracts, or
maxSubmissionCost.
The contracts deployment (7+ contracts + initialization) needs more gas
than the factory deployment (single contract creation).
Instead of using a hardcoded default, read gasLimitForL2FactoryDeployment
from the TokenBridgeCreator contract. The caller can still override via
the maxGasForFactory parameter.
Replace the separate enqueue* and create* prepare functions with a single
implementation that estimates retryable gas from parent chain state and
does not require an orbit chain connection.

The createTokenBridge orchestrator now calls registerNewNetwork explicitly
before waiting for retryables, since the prepare functions no longer do
this internally.
Add zod v4 validation schemas and transform functions for all SDK
operations. Includes shared primitives (address, hex, bigint schemas),
per-function schema/transform pairs, and viem client factory helpers.
Abitype's peer dep on zod ^3 caused pnpm to keep zod@3.22.4 in the tree,
creating non-portable abitype resolution paths that TypeScript couldn't
name in .d.ts output.
@yahgwai yahgwai reopened this Apr 8, 2026
yahgwai and others added 10 commits April 10, 2026 16:05
The enqueue-token-bridge-deployment refactor removed orbitChainPublicClient
from createTokenBridgePrepareTransactionRequest and its setWethGateway
variant. Update schemas to match.
Add overrides for vite, flatted, picomatch, brace-expansion, and yaml
to resolve transitive vulnerabilities in dev tooling (vitest, eslint,
typescript-eslint, @wagmi/cli, ts-morph, patch-package).
…ction schemas

The build* actions take account: Address, not a private key. The schemas
should only require what the function actually needs.
# Conflicts:
#	package.json
#	pnpm-lock.yaml
Add publicClientSchema, parentChainPublicClientSchema, and
actionWriteBaseSchema to common.ts. Add withPublicClient helper to
viemTransforms.ts. Update 26 schema files to extend base schemas
instead of redeclaring fields. Simplify 9 destructure-and-spread
transforms to use withPublicClient.
Inline parentChainPublicClientSchema directly instead of assigning
it to a local alias. Use .extend().strict() instead of z.strictObject()
with .shape extraction.
Add connection transform functions (withPublicClient, withParentChainPublicClient,
withChainSign, withParentChainSign, withChildChainSign, withParentReadChildSign,
withPublicClientPositional, withPublicClientOptionalChain) to viemTransforms.ts.

Every schema now has its transform baked in via .transform(), eliminating
separate transform/resolver exports. Schemas export a single pre-transformed
schema that consumers use directly.

Move upgradeExecutor ?? false default into actionWriteBaseSchema.
@yahgwai yahgwai changed the base branch from main to feat/enqueue-token-bridge-deployment April 16, 2026 15:36
yahgwai added 2 commits April 22, 2026 12:42
…t type

Replace the inline `typeof import(...)` form with a regular named import.
Matches the style used by the sibling schemas in the same file and keeps
the import list in one place. No behavior change -- both forms produce a
type-only reference that TypeScript erases.
Comment thread src/scripting/schemas/common.ts Outdated

export const addressSchema = z
.string()
.regex(/^0x[0-9a-fA-F]{40}$/, 'Invalid Ethereum address')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

viem has isHex, isAddress, etc. predicates we can use

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, updated

Comment thread package.json
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we sure we need these?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, removed

yahgwai added 7 commits April 22, 2026 14:50
…tion

Replace regex-based hex and address validators with viem's isHex and
isAddress. isAddress does EIP-55 checksum validation on mixed-case
addresses, catching a class of typo that the regex silently passed.
Same module viem is already a dependency of the SDK -- no new deps.
Removed vite, flatted, picomatch, brace-expansion, and yaml from
pnpm.overrides. Tested by removing them and running pnpm install +
pnpm audit-ci -- the natural version resolution satisfies the former
override floor in every case, and audit-ci still passes. Kept tmp
(active CVE) and zod (prevents a v3/v4 dual install via abitype).
The SDK function isTokenBridgeDeployed was removed as unused in the
merge from feat/enqueue-token-bridge-deployment. Clean up the scripting
references that depended on it:

- delete src/scripting/schemas/isTokenBridgeDeployed.ts
- drop the re-export from src/scripting/schemas/index.ts
- drop the type-level assertion in schemas.type.test.ts

Users wanting the same check can call
createTokenBridgeFetchTokenBridgeContracts and test the returned
router/gateway addresses for the zero address.
The coverage test framework derives test values from the schema's regex
patterns. Stripping the regex in favor of bare refine() left the generator
falling back to 'string_0', which fails address/hex validation. Layer the
viem checks on top of the regex so both the generator and runtime
validation work.
Base automatically changed from feat/enqueue-token-bridge-deployment to main April 22, 2026 14:44
@yahgwai yahgwai enabled auto-merge (squash) April 22, 2026 14:48
The regex layer was subsumed by viem's isHex/isAddress and was only
retained to feed the schema coverage test generator. Drop it here;
the coverage generator in feat/schema-coverage will need to learn
about the address/hex formats directly (follow-up on that branch).
yahgwai added 2 commits April 22, 2026 16:43
Replace the regex with viem's isHex + size(v) === 32. Matches the
style of hexSchema / addressSchema (refine-backed, no regex).
Coverage generator follow-up lands on feat/schema-coverage.
Replace the regex with isHex + v.length === 66 (0x prefix plus 64 hex
chars). Matches the style of hexSchema / addressSchema. Coverage
generator follow-up lands on feat/schema-coverage.

Supersedes the earlier isHex + size attempt; viem's size() rounds
odd-length hex up via Math.ceil, so it couldn't strictly enforce
length. An explicit length check is accurate.
@yahgwai yahgwai merged commit 6089ab1 into main Apr 22, 2026
10 checks passed
@yahgwai yahgwai deleted the feat/zod-schema branch April 22, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants