Skip to content

feat(nodejs-server-wallets): Dynamic native gas sponsorship, Solana support, idempotent transfers - #71

Open
emtesenair wants to merge 2 commits into
mainfrom
feat/nodejs-server-wallets-dynamic-gasless
Open

feat(nodejs-server-wallets): Dynamic native gas sponsorship, Solana support, idempotent transfers#71
emtesenair wants to merge 2 commits into
mainfrom
feat/nodejs-server-wallets-dynamic-gasless

Conversation

@emtesenair

Copy link
Copy Markdown
Collaborator

Replaces ZeroDev/Pimlico with Dynamic's native gas sponsorship, adds Solana
alongside EVM, and adds retry-safe (idempotent) transfers.

Gas sponsorship

  • EVM — EIP-7702 delegation to Dynamic's UGD contract plus an EIP-712
    AuthorizedExecutions intent, relayed by Dynamic. No bundler, paymaster, or
    smart account.
  • SVM — fee-payer replacement. Sponsorship must precede signing (swapping the
    fee payer changes the message), and your server broadcasts rather than a relayer.
  • Delegated wallets on both chains, plus a sign-here/relay-there split: signing
    needs the delegated credentials, relaying needs only the environment API token.

Structure

src/evm/ and src/svm/ mirror each other. Chain-specific library code is
lib/<feature>/<chain>.ts and the two chains never import each other; unsuffixed
lib/ modules are chain-agnostic. Chain dispatch uses exhaustiveness-checked
switches, so adding a chain fails the build at every site that needs work.

Idempotency

lib/transfer/ presents one call shape for either chain — native or token, server
or delegated signer — and picks the right retry mechanism underneath.
src/examples/idempotency/ shows each mechanism in isolation. IDEMPOTENCY.md
documents both with measurements.

The two chains need opposite handling, and this is the part worth reviewing.
EVM derives the intent nonce from a business key, and the delegate contract's
unordered bitmap admits it exactly once per wallet. On SVM the transaction id is
signatures[0] — the fee payer's, which under sponsorship is Dynamic's sponsor —
so re-signing the wallet's signature is deduped by Solana, and it is rebuilding
with a fresh blockhash that yields a second executable transaction. The safe retry
unit there is the signed bytes: sign once, persist, rebroadcast verbatim.

Try it

cd examples/nodejs-server-wallets
cp .example.env .env   # add DYNAMIC_API_TOKEN + DYNAMIC_ENVIRONMENT_ID
pnpm install

pnpm smoke             # offline: type-check + argument validation
pnpm smoke --all       # + signing and sponsored transactions (spends relayer budget)

Requires EVM/SVM Gas Sponsorship enabled for the environment.

Also

  • @dynamic-labs-wallet/{node,node-evm,node-svm} → 1.0.105; unused deps dropped;
    all versions pinned exactly.
  • pnpm smoke — tiered runner (offline / signing / onchain) over the real CLI
    entrypoints, so expensive tiers are opt-in.
  • Per-directory READMEs and a project tree in the root README.

…upport, idempotent transfers

Replace ZeroDev/Pimlico with Dynamic's native gas sponsorship, and restructure the
example around two chains.

Gas sponsorship:
- EVM: EIP-7702 delegation to Dynamic's UGD contract plus an EIP-712
  AuthorizedExecutions intent, relayed by Dynamic. No bundler, paymaster, or smart
  account.
- SVM: fee-payer replacement. Sponsorship must precede signing, since swapping the
  fee payer changes the message, and your server broadcasts rather than a relayer.
  Server wallets use signTransaction({ sponsor: true }), which returns the sponsored,
  signed transaction in one call. Delegated wallets split it, since they hold no
  caller-side key shares.
- Delegated wallets on both chains, including a sign-here/relay-there split.

Solana support:
- New src/svm/ mirroring src/evm/: wallet, sign-message, send-transaction, and
  delegated variants.
- Chain-specific library code split as lib/<feature>/<chain>.ts. EVM and SVM modules
  never import each other; unsuffixed lib modules are chain-agnostic.

Idempotent transfers:
- lib/transfer/ presents one call shape for either chain, native asset or token,
  server or delegated signer, and selects the right retry mechanism underneath.
- src/examples/idempotency/ shows each chain's mechanism in isolation.
- IDEMPOTENCY.md documents both with measurements.

The two chains need opposite handling, which is the main thing this documents. EVM
derives the intent nonce from a business key, and the delegate contract's unordered
bitmap admits it exactly once per wallet. On SVM the transaction id is
signatures[0] — the fee payer's, which under sponsorship is Dynamic's sponsor — so
re-signing the wallet's signature is deduped, and it is rebuilding with a fresh
blockhash that produces a second executable transaction. The safe retry unit there is
the signed bytes: sign once, persist, rebroadcast verbatim.

Also:
- Bump @dynamic-labs-wallet/{node,node-evm,node-svm} to 1.0.105; drop unused deps;
  pin all versions exactly.
- Add `pnpm smoke`: a tiered runner (offline / signing / onchain) over the real CLI
  entrypoints, so the expensive tiers are opt-in.
- Add per-directory READMEs and a root project tree.
@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project sidebar-example with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project dynamic-morpho with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project dynamic-gasless-starter with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project lifi with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project dynamic-aave with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project blindpay with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deployment failed for project circle-gateway with the following error:

There is no GitHub account connected to this Vercel account.

@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
kamino Error Error Aug 20, 2026 6:01am
nextjs-iron-ramp Ready Ready Preview Aug 20, 2026 6:01am
predictions-market-demo Ready Ready Preview Aug 20, 2026 6:01am

Request Review

…quire RPC_URL

Replaces the hand-rolled EIP-712 sponsorship intent with the SDK's first-class
delegated gasless API (1.0.106+) and upgrades the Dynamic packages to 1.0.109.

- Delegated EVM sponsorship now goes through delegatedSendSponsoredTransaction /
  delegatedSignSponsoredTransaction instead of assembling AuthorizedExecutions,
  resolving a relayer, and signing typed data by hand. Drops ~130 lines from
  src/lib/gasless/evm.ts.
- Delegated SVM sponsorship uses delegatedSignTransaction({ sponsor: true }),
  folding the separate sponsorTransaction call into one request.
- userId is plumbed through the delegated credentials and required at the gasless
  boundaries, where a sponsored transaction has to be attributed to the wallet's
  owner. Documented in both wallet.json templates and delegated READMEs.
- Adds an autoDelegate option. It defaults to on, and is the only reason the EVM
  path needs an RPC: an eth_getCode delegation check plus the EOA nonce that a
  7702 authorization commits to. Resolved lazily so --pre-sign, which turns it
  off, runs with no RPC_URL at all.
- RPC_URL is now required for EVM operations with no public fallback. The public
  Base Sepolia endpoint is rate limited and intermittently down, which made a
  correct setup look broken.
- Removes an unused client from the SVM delegated send and a duplicated SvmClient
  type alias.

Docs swept for the migration: the delegated READMEs described the hand-rolled
architecture and claimed no first-class API existed, and the README listed
RPC_URL as optional. Also documents --pre-sign and the Solana devnet funding step.
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.

1 participant