Repository navigation
feat(wallet): Privy server wallets as the privy signer backend - #729
Closed
fengtality wants to merge 5 commits into
Closed
fengtality wants to merge 5 commits into
fengtality wants to merge 5 commits into
Conversation
fengtality
force-pushed
the
feat/signer-seam
branch
from
October 20, 2026 03:58
99f5326 to
eae1efd
Compare
… error mapping Credentials come from PRIVY_APP_ID, PRIVY_APP_SECRET and PRIVY_AUTHORIZATION_KEY only. The authorization signature matches @privy-io/node (RFC 8785 payload, P-256 low-S DER). Wallet ids are validated before they reach a URL. Privy errors map to 4xx; Privy's error text is never returned to the caller.
…te-privy routes
The registry maps the 'privy' signer kind to the Privy backend, so every execute route
signs through Privy for a privy wallet with no connector change. Solana: the backend
wraps the seam's message in a transaction, has Privy sign it, checks the returned
message is unchanged and returns only the wallet's signature. Ethereum: the populated
transaction goes to eth_signTransaction and the chokepoint checks it before sending.
Privy wallet records (id and address only) are in conf/wallets/{chain}/privy-wallets.json.
[High impact] The PR appears safe to merge; no new actionable issues remain. SummaryAdds Privy-backed signing for Solana and Ethereum, plus routes to add and create Privy wallets.
|
fengtality
force-pushed
the
feat/privy-signer
branch
from
October 20, 2026 04:01
a408309 to
f3106db
Compare
…02; SDK payload fixture updateListStore runs read-change-write on one list store with no other update to the same file in between; add-privy and DELETE /wallet/remove use it. A failure while reading Privy's response body is a 502 like a failed request. The authorization signature test now verifies against payload bytes taken from @privy-io/node.
… name add-privy in the 404 add-external and the hardware save (now upsertHardwareWallet) read, change and write their list under the same per-file lock as add-privy and removal, so concurrent saves keep every entry. The 404 for an unknown wallet names POST /wallet/add-privy.
fengtality
added a commit
that referenced
this pull request
Oct 20, 2026
…and Privy wallets (#673, #682) Every Gateway route that sends a transaction gets a build-* twin that returns the unsigned transaction, and POST /chains/{chain}/submit broadcasts what the caller signed. Every execute route signs through one signer seam per chain, with local, hardware, external and Privy wallets behind it. This is the build half of the old #721 and the content of #727, #730, #728, #732 and #729, on top of the launch connectors. Solana build mode (from #721) - A build-* route runs the connector's own code and captures the transaction at Solana.sendAndConfirmTransactionForWallet instead of signing it: simulated, compute budget sized, fresh blockhash, ephemeral keypairs partial-signed, fee-payer slot empty. A broadcast attempted during a build throws; nothing is sent. - Routes: router build-swap and build-quote; clmm build-swap, build-open, build-add, build-remove, build-collect-fees, build-close and build-create-pool; amm build-swap, build-add, build-remove and build-create-pool; launch build-swap and build-create-token; POST /chains/{chain}/build-transaction for caller instructions; and POST /chains/{chain}/submit, which re-merges the ephemeral signatures and verifies every signature and the blockhash before it broadcasts. - The build shape on every build route: extraInstructions, feePayer, format (transaction or instructions), memo, references (Solana Pay) and priority (normal, high, urgent). - platformFee on builds, paid to a recipient the caller names (Jupiter through its feeAccount, other venues by a transfer after the operation). Router quotes take platformFeeBps. - pancakeswap-sol build routes are refused by name. poll reports currentBlockHeight beside the slot. - Build routes are behind the API-token gate with their execute routes; submit stays public like poll. Build coverage (#727) - One build response for an operation of several transactions; a wide Meteora DLMM open, add, remove, close or collect builds as one response. - collect-fees and build-collect-fees for Meteora DAMM v2. - build-claim-creator-fees and build-migrate; creator-fee claims on meteora and raydium. - pump: a dev-buy create names its lookup table, or has one made for it; each new lookup table gets its own slot, and a create after a new table compiles with the build's fee payer. - build-transaction takes feePayer, memo and priority. A legacy build's compute is sized against the RPC's own blockhash. - raydium AMM v4 add gives the non-limiting side its slippage headroom. Signer seam (#730) - The signer seam interface and the wallet record. Every Solana and EVM transaction is signed through it. - External wallets: Gateway holds no key, and a route that would sign for one refuses and names its build twin. - The key-handling helpers the seam replaced are deleted, with the old ledger helpers. - The route-coverage test: every route that sends a transaction is listed with its build twin, and only the seam signs. EVM build and submit (#728) - build-* twins and submit for every EVM transaction route. A build returns the unsigned transaction with the approvals it needs first. - Tests for build mode, approvals, submit and the EVM build routes. - The uniswap execute-quote Permit2 check moved to Ethereum.requirePermit2Allowance, so its own test (executeQuote-permit2-expiration.test.ts) is deleted; the EVM build-mode tests cover the Permit2 path with the max uint48 expiration. The last build twins (#732) - Solana build-wrap and build-unwrap, and launch build-quote. The route table has no gaps. Privy wallets (#729) - A Privy server-wallet REST client with request signing and error mapping. - The privy signer backend on the seam, and the add-privy and create-privy routes. - EVM quantities go to Privy as minimal hex. Wallet list stores change through updateListStore, one update at a time. - The Privy seam test calls the EVM chokepoint the way #728 left it. openapi.json is regenerated. Closes #682
Contributor
Author
|
Consolidated into the single draft build-and-submit PR #734. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Privy server wallets as the
privysigner backend on the signer seam (#673, basefeat/signer-seam). Privy holds the key and signs; Gateway builds and sends. Every execute route works for aprivywallet with no connector change, because the seam's chokepoints get the signer from the registry.Replaces the closed #649 and #618, using Privy's current REST API (
@privy-io/node0.36 was read as the spec).What changes
src/wallet/privy/privy-client.tsis a small REST client forGET /v1/wallets/{id},POST /v1/walletsandPOST /v1/wallets/{id}/rpc(signTransaction,eth_signTransaction).Credentials come only from
PRIVY_APP_ID,PRIVY_APP_SECRETandPRIVY_AUTHORIZATION_KEYin the environment. There is nothing in conf, the templates or request bodies.The
privy-authorization-signaturematches the SDK. The payload is RFC 8785{version, method, url, body, headers}, signed with ECDSA P-256 / SHA-256, low-S, DER. It was checked byte for byte againstformatRequestForAuthorizationSignature, and the signatures verify with noble'slowScheck. Aprivy-request-expiry(15 min) is signed in.The wallet id must match
^[a-z0-9]{16,64}$before it reaches a URL, and it is stillencodeURIComponent-ed. This is the SSRF fix from feat / Add execute-tx endpoint with Privy wallet integration #618.Privy errors map to clear Gateway errors:
PRIVY_AUTHORIZATION_KEYPrivy's error text is not returned and is logged only at debug level.
canonicalize(CJS, about 40 lines) is the only new dependency. The SDK itself is not used: it loads ESM-onlyjose, which Jest cannot load.src/wallet/signers/privy.tsregisters insignerBackendsasprivy.eth_signTransactionwith minimal hex quantities (0x3). The chokepoint checks the sender and fields before it broadcasts.POST /wallet/add-privy {chain, privyWalletId, setDefault?}reads the wallet from Privy, checks its chain type and address, and stores{address, privyWalletId, addedAt}inconf/wallets/{chain}/privy-wallets.json.POST /wallet/create-privy {chain, setDefault?}creates a wallet owned by the authorization key's public key, then adds it.GET /walletlists Privy wallets withsigner: 'privy', andDELETE /wallet/removeremoves the record. The wallet itself stays in Privy.docs/signer-seam.mdhas a new Privy section. Operation ids, the route list andopenapi.jsonare updated.Scope
One authorization key per Gateway, for Gateway and Hummingbot API users. Wallets that another app signs with its own Privy session signers are not designed for here.
Tests
Privy is stubbed at the HTTP edge only (
global.fetch). The stub checks the Basic auth header and verifies the authorization signature against the generated key.privy-seam.test.ts: aprivywallet record goes through the real registry and the real Solana and Ethereum chokepoints. Privy signs, the result is broadcast, and the sent transaction verifies. A policy denial is a 403 and nothing is sent.privy-signer.test.ts: co-signer signing, a message changed by Privy is rejected, a non-signer wallet is refused without a Privy call, and EVM field mapping.privy-client.test.ts: request shape, request signature, wallet id validation (no request is made), the error mapping, and missing credentials.privy-wallet.routes.test.ts: add, list, sign-kind, remove; wrong chain; 404; malformed id; address already local; create.Local evidence (stacked PR, so the
ciworkflow does not run). Each check ran on the final commit:pnpm buildpasses.pnpm lint: 0 errors. The 36 warnings are all in files this PR does not touch.pnpm test -w 3: 204 suites and 1916 tests pass.pnpm generate:openapiwas run.Not run live: Privy credentials were not given, so no live Privy swap was run.
🤖 Generated with Claude Code