Skip to content

feat(cli)!: migrate to Sequence V3 OMSClient (email-login embedded wallet)#120

Open
AkshatGada wants to merge 15 commits into
mainfrom
feat/oms-v3-wallet-migration
Open

feat(cli)!: migrate to Sequence V3 OMSClient (email-login embedded wallet)#120
AkshatGada wants to merge 15 commits into
mainfrom
feat/oms-v3-wallet-migration

Conversation

@AkshatGada

Copy link
Copy Markdown
Collaborator

Summary

Migrates polygon-agent-cli from the Sequence dapp-client wallet model (browser-approval sessions + on-chain permission scoping) to the Sequence V3 OMS embedded-wallet model (@0xsequence/typescript-sdk, email-OTP login). Breaking change — the wallet is a new address space; users re-onboard via wallet login.

What changed

New wallet model

  • wallet login --email <addr> (email OTP) replaces wallet create (browser approval). wallet logout added. Start+complete happen in one process (OTP is in-memory only).
  • Session credential persists encrypted on disk (EthereumPrivateKeyCredentialSigner + file-backed StorageManager); survives process restarts — verified headless on Polygon mainnet.
  • Wallet address is deterministic per email and identical across all EVM chains. Sessions last ~1 week.

New libs

  • lib/oms-client.tsgetOmsClient(walletName) singleton
  • lib/oms-storage.ts — encrypted file StorageManager + credential-key persistence
  • lib/oms-tx.tsrunOmsTx, drop-in for the old tx primitive; ported fee selection (prefer native or USDC, gated on affordability); sequential multi-tx for deposit (non-atomic)
  • lib/tx-dispatch.tsrunTx indirection used by all command call sites

Commands — all 17 tx call sites route through runTx. balances migrated to oms.indexer. New call command (arbitrary calldata) already on main, retained. x402-pay funding + EIP-3009 unchanged (EOA-based).

Removed (one-way)lib/dapp-client.ts, lib/relay-client.ts, the connector-ui package + its deploy workflow, the shared x25519/xchacha20 session crypto, the Sapient permission flow, and all --contract/--usdc-limit/spend-limit/--defi flags. Legacy @0xsequence/dapp-client/wallet-*/relay deps pruned.

Config / env

  • setup --oms-publishable-key <key> --oms-project-id <proj_...> persists OMS creds to builder.json.
  • bootstrapOmsConfig() loads SEQUENCE_PUBLISHABLE_KEY + SEQUENCE_OMS_PROJECT_ID, and also SEQUENCE_PROJECT_ACCESS_KEY (Trails/indexer key) from disk.
  • Trails key resolution unified across swap/deposit/withdraw: TRAILS_API_KEY → SEQUENCE_PROJECT_ACCESS_KEY → builder.json.accessKey.

Docsskills/* + README + CLAUDE.md rewritten for the email-login flow; all old-model references removed.

⚠️ Accepted regressions (intentional, per product decision)

  • No on-chain permission scoping — the V3 wallet can call any contract and spend any amount it holds. No per-contract whitelist or spend limits (these don't exist in OMS). Guard spending in agent logic.
  • No browser-approval trust model — the CLI holds an extractable credential key on disk.
  • deposit is non-atomic — approve + supply submit as two sequential txs.
  • SDK is alpha@0xsequence/typescript-sdk@0.1.0-alpha.2, pinned exactly.

Verification (Polygon mainnet)

  • Headless persistence: auth → process restart → sign, no re-auth ✅
  • Live broadcasts: send-token, send-native, call (real tx hashes) ✅
  • balances single + multi-chain via oms.indexer
  • deposit builds correct 2-tx bundle; swap POL→USDC builds a valid Trails intent ✅
  • Typecheck + lint clean across the workspace (connector-ui/shared removed)

Commits

  • feat(cli): add OMS path behind flag
  • refactor(cli)!: remove dapp-client/connector-ui legacy, OMS is the only path
  • docs(cli): update skills + README
  • refactor(cli): bootstrap Trails key + unify resolution; drop stale legacy notes

Phase 1 + core Phase 2 of the migration from @0xsequence/dapp-client
(delegated browser-approved sessions) to @0xsequence/typescript-sdk
(OMSClient embedded wallet, email login). Additive and flag-gated —
the legacy path is unchanged and remains the default.

New:
- lib/oms-storage.ts: encrypted file-backed StorageManager + persisted
  EthereumPrivateKeyCredentialSigner key (survives process restarts).
- lib/oms-client.ts: getOmsClient(walletName) singleton.
- lib/oms-tx.ts: runOmsTx — drop-in for runDappClientTx; maps the
  {to,data,value}[] interface onto oms.wallet.sendTransaction with ported
  fee selection (prefer native or USDC, gated on availableRaw).
- lib/tx-dispatch.ts: runTx routes to OMS when POLYGON_AGENT_OMS is set.
- wallet login (email OTP) + wallet logout; list/address handle OMS pointers.

Changed:
- storage.ts: export GCM helpers; add OmsConfig/OmsWalletPointer + helpers
  and bootstrapOmsConfig.
- All 17 runDappClientTx call sites now import runTx via the dispatch shim.
- utils.ts: getReadRpcUrl with public-RPC fallback (OMS has no nodes access key).
- x402-pay receipt poll uses getReadRpcUrl instead of session.projectAccessKey.

Verified end-to-end on Polygon mainnet: email login -> persisted session ->
call with POLYGON_AGENT_OMS=1 -> on-chain USDC transfer
(tx 0xb5e35f2f74fcdb75ccd453e23af4e0d3a88f60e383f00fb2e0e43cbf41613ba1).
… only path

Completes the migration from the dapp-client delegated-session model
(browser approval + relay + on-chain Sapient permission scoping) to the
Sequence V3 OMSClient embedded-wallet model. OMS is now the only path.

Removed:
- packages/connector-ui (browser approval UI) + its deploy workflow
- packages/shared (x25519/xchacha20 relay session crypto)
- src/lib/dapp-client.ts, src/lib/relay-client.ts
- wallet create/import (+ WalletCreateUI), AUTO_WHITELISTED_CONTRACTS,
  spending-limit / --contract scoping flags, relay storage helpers,
  bootstrapAccessKey, SequenceIndexer usage
- 12 legacy @0xsequence/* + tweetnacl deps (pnpm: +95 -894 packages)

Changed:
- balances + balances Ink UI now read via oms.indexer (publishableKey auth);
  no more projectAccessKey
- withdraw/x402 receipt polling uses getReadRpcUrl (public-RPC fallback)
- all tx commands resolve wallets via loadOmsWalletPointer; chain defaults
  to polygon (OMS wallets are chain-agnostic)
- tx-dispatch.runTx now wraps runOmsTx unconditionally
- CLAUDE.md updated for the OMS-only structure

Verified live on Polygon mainnet with no env flag: wallet login, balances
via oms.indexer, and a USDC transfer via `call`
(tx 0x1c7ff1df746bacab7930dc24ada694fa9061976164871ad3fb6bf3940eec2bdc).
Remove all references to the removed wallet create / browser approval /
--contract scoping / connector-ui flow across SKILL.md files and README.
Document wallet login (email OTP), setup --oms-* credentials, the call
command, and the no-permission-scoping V3 model.
Drop the dead "re-create with wallet create --contract" notes and the
Sapient-era error handling ("No signer supported", session-permission
rejection) from deposit and withdraw — these referred to the removed
dapp-client permission-scoping model and can't occur on the OMS path.
Deposit/withdraw now submit through runOmsTx directly; OMS session
errors are handled in the primitive. Also fix the setup TTY hint to
point at `wallet login` instead of the removed `wallet create`.
return Uint8Array.from(Buffer.from(decrypt(cipher), 'hex'));
}
const keyHex = Buffer.from(randomBytes(32)).toString('hex');
fs.writeFileSync(file, JSON.stringify(encrypt(keyHex)), { mode: 0o600 });
AkshatGada and others added 4 commits July 1, 2026 00:02
Add a `wallet login-browser` subcommand that signs in with Google through the
SDK's OIDC + PKCE redirect flow, using a short-lived localhost callback server.
The resulting session persists identically to email login, so balances, tx and
address resume with no re-login. The funding step is chained after a successful
login (skip with --no-fund).

- oidc-callback-server.ts: loopback server that captures the single callback URL
- oms-client.ts: pass the mandatory redirectAuthStorage; SEQUENCE_OIDC_RELAY_URI override
- oms-storage.ts: FileStorageManager subdir arg, isolating transient OIDC state
- storage.ts: widen loginMethod to email|oidc|google; email now optional
- operations.ts: extract showFunding so `fund` and post-login reuse one path

This is the same-machine flow (browser and CLI co-located). Remote login over a
relay is a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A small Cloudflare Worker + Durable Object that lets the CLI complete browser
login from any machine, including a remote server where a localhost callback
can't be reached. The browser is redirected to the relay with the OAuth
code+state; the CLI polls for them and finishes the exchange itself. The PKCE
verifier never leaves the CLI, so the relay alone cannot complete a login.
Sessions are keyed by the OIDC state, single-use, with a 10-minute TTL.

Not yet wired into the CLI: the --remote poll path lands once Sequence
allowlists the relay's /api/oidc/cb as a redirect target. Deploy with
`npx wrangler` (kept out of the workspace dep graph to satisfy the repo's
trust policy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gration

# Conflicts:
#	packages/connector-ui/CHANGELOG.md
#	packages/connector-ui/package.json
#	packages/connector-ui/src/App.css
#	packages/connector-ui/src/index.css
#	packages/shared/CHANGELOG.md
#	packages/shared/package.json
#	pnpm-lock.yaml
@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown

Code review

Found 3 issues. Checked for bugs and CLAUDE.md compliance.

  • Bug: wallet remove always throws "Wallet not found" due to deleteOmsWallet deleting the pointer file before deleteWallet checks for it
  • Team standards: Definite assignment assertions (!) in new file oidc-callback-server.ts
  • Team standards: showFunding uses 4 positional parameters instead of a params object

See inline comments for details.

@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown

Detailed review findings

1. Bug in wallet.ts:284-289wallet remove always throws "Wallet not found"

deleteOmsWallet(name) deletes the wallet pointer file at wallets/<name>.json before deleteWallet(name) checks for it. Since the file is already gone, deleteWallet returns false, and the handler always throws Wallet not found — even when the wallet was successfully removed.

See storage.ts L284-289 and wallet.ts L284-289.

Fix: swap the call order so deleteWallet runs before deleteOmsWallet.


2. Team standards violation in oidc-callback-server.ts:52-53 — definite assignment assertions

Definite assignment assertions (let x!: T) bypass TypeScript's static guarantees. The team standards say: No non-null assertions (!) — narrow the type instead. Fix: initialize with no-op stubs that get overwritten by the Promise executor.


3. Team standards violation in operations.ts:333-338 — positional parameters

showFunding has 4 positional parameters including a defaulted chainId and optional opts. The team standards say: Params objects over positional arguments for functions with 2+ parameters. Refactor to a params object.

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