Skip to content

Add Privy wallet integration toolkit#25

Merged
tilo-14 merged 17 commits intomainfrom
add-privy
Feb 16, 2026
Merged

Add Privy wallet integration toolkit#25
tilo-14 merged 17 commits intomainfrom
add-privy

Conversation

@tilo-14
Copy link
Contributor

@tilo-14 tilo-14 commented Feb 16, 2026

Summary

  • Add toolkits/sign-with-privy/ with Node.js and React examples for light-token operations signed via Privy wallets (devnet)
  • Node.js: server-side scripts for transfer, wrap, unwrap, load, balances, transaction history
  • React: browser app with embedded wallet signing, balance queries, transfer form
  • Setup scripts for creating test mints and funding wallets
  • Update typescript-client examples to use beta SDK dist-tag
  • Update toolkits README and root README with sign-with-privy entry

Test plan

  • Verify npm install resolves workspaces
  • Run Node.js scripts against devnet (npm run balances in toolkits/sign-with-privy/nodejs/)
  • Run React dev server (npm run dev in toolkits/sign-with-privy/react/)
  • Verify all README links resolve correctly

🤖 Generated with Claude Code


Open with Devin

tilo-14 and others added 17 commits February 11, 2026 13:45
Server-side (nodejs) and client-side (react) Privy wallet examples
for light-token transfers, wrap, unwrap, load, and balances.

Restructured privy/ layout:
- nodejs/: server wallet signing via @privy-io/node
- react/: embedded wallet signing via @privy-io/react-auth
- scripts/: setup helpers (mint creation, SPL interface registration)

Transfer creates destination associated token account idempotently
before transferring.
React hooks (useTransfer, useUnwrap) now call high-level SDK functions
(createTransferInterfaceInstructions, createUnwrapInstructions) instead
of manually assembling instructions. Shared signAndSendBatches helper
handles multi-tx flows from batched instruction arrays.

Balance hooks (react + nodejs) refactored to per-mint accumulator
pattern that queries all mints in one pass instead of single-mint.
TokenBalance now exposes hot/cold/spl/t22/unified breakdown.

Other changes:
- useWrap: imports from /unified subpath, uses idempotent ATA create
- unwrap (nodejs + react): auto-detect token program from mint owner
- mint-light-token script: --spl flag for SPL token program mints
- mint-spl script: auto-detect token program from mint account
- Remove standalone load.ts (load is handled by transfer/unwrap SDK)
Remove hidden wrap-then-transfer flow from Send button.
Add explicit Unify button for wrapping SPL/T22 into unified balance.
Send only enabled when unified balance > 0.
@tilo-14 tilo-14 merged commit da23591 into main Feb 16, 2026
18 checks passed
@tilo-14 tilo-14 deleted the add-privy branch February 16, 2026 00:16
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

const getOrCreate = (mintStr: string) => {
let entry = mintMap.get(mintStr);
if (!entry) {
entry = { spl: 0n, t22: 0n, hot: 0n, cold: 0n, decimals: 9 };
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 Hardcoded decimals: 9 in React balance hook causes incorrect transfer amounts for non-9-decimal tokens

The useLightTokenBalances hook hardcodes decimals: 9 for every token entry. This value propagates through the transfer flow and is used to compute the raw token amount sent on-chain.

Root Cause and Impact

At toolkits/sign-with-privy/react/src/hooks/useLightTokenBalances.ts:39, all mint entries are created with decimals: 9:

entry = { spl: 0n, t22: 0n, hot: 0n, cold: 0n, decimals: 9 };

This decimals field flows through TransferForm.tsx:76 into useTransfer.ts:42:

const tokenAmount = Math.floor(amount * Math.pow(10, decimals));

For a token with 6 decimals (e.g., USDC — explicitly mentioned in the README as a wrapping example), when a user enters amount 1:

  • Actual: tokenAmount = 1 * 10^9 = 1,000,000,000
  • Expected: tokenAmount = 1 * 10^6 = 1,000,000

This sends 1000x more tokens than the user intended. The same hardcoded decimals also causes formatBigint(total, balance.decimals) in TransferForm.tsx:147 to display balances at the wrong scale.

Impact: Users transferring any token with decimals ≠ 9 will send a drastically wrong amount, potentially draining their balance.

Prompt for agents
In toolkits/sign-with-privy/react/src/hooks/useLightTokenBalances.ts, the decimals field is hardcoded to 9 on line 39. The actual decimals should be fetched from the on-chain mint account data (stored at byte offset 44 in the SPL mint layout) or from the getAtaInterface parsed response. One approach: after populating the mintMap, fetch each mint's account info via rpc.getAccountInfo(mint) and parse the decimals byte at offset 44 of the data buffer. Then set entry.decimals to the parsed value. The same hardcoded decimals issue exists in the Node.js balances.ts at toolkits/sign-with-privy/nodejs/src/balances.ts line 45.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

signatures.push(sig);
}

return signatures[signatures.length - 1];
Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 Node.js transfer.ts and unwrap.ts return undefined when SDK returns empty instruction batches

When createTransferInterfaceInstructions or createUnwrapInstructions returns an empty array, the functions return undefined instead of a string signature.

Detailed Explanation

In toolkits/sign-with-privy/nodejs/src/transfer.ts:60:

return signatures[signatures.length - 1];

If instructions (from createTransferInterfaceInstructions) is [], the for loop never executes, signatures stays empty, and signatures[-1] evaluates to undefined. The same pattern exists in toolkits/sign-with-privy/nodejs/src/unwrap.ts:68.

The React equivalent (toolkits/sign-with-privy/react/src/hooks/signAndSendBatches.ts:43) correctly handles this:

return signatures.length > 0 ? signatures[signatures.length - 1] : null;

Impact: The caller at line 75 logs Transfer signature: undefined, and any downstream code relying on a valid signature string will break silently.

Suggested change
return signatures[signatures.length - 1];
if (signatures.length === 0) throw new Error('Transfer returned no instructions');
return signatures[signatures.length - 1];
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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