Privacy SDK for GrimSwap - Ring signatures & stealth addresses for Uniswap v4 on Unichain.
npm install @grimswap/sdk viem- Ring Signatures (LSAG): Hide sender identity by mixing with decoy addresses
- Stealth Addresses (ERC-5564): One-time addresses for recipient privacy
- Private Swaps: Execute swaps with complete sender and recipient privacy
- Announcement Scanner: Find payments sent to your stealth addresses
import { generateStealthKeys } from '@grimswap/sdk';
// Generate once, store securely
const keys = generateStealthKeys();
console.log('Share this with senders:', keys.stealthMetaAddress);
// Keep these secret:
// keys.spendingPrivateKey
// keys.viewingPrivateKeyimport { generateStealthAddress } from '@grimswap/sdk';
// Generate a one-time address for the recipient
const { stealthAddress, ephemeralPubKey, viewTag } = generateStealthAddress(
recipientMetaAddress
);
// Send funds to stealthAddress
// Include ephemeralPubKey in announcementimport { scanAnnouncements } from '@grimswap/sdk';
import { createPublicClient, http } from 'viem';
import { unichainSepolia } from 'viem/chains';
const publicClient = createPublicClient({
chain: unichainSepolia,
transport: http(),
});
const payments = await scanAnnouncements({
publicClient,
viewingPrivateKey: keys.viewingPrivateKey,
spendingPublicKey: keys.spendingPublicKey,
fromBlock: 0n,
});
for (const payment of payments) {
console.log('Found payment:', payment.amount, 'at', payment.stealthAddress);
}import { deriveStealthPrivateKey } from '@grimswap/sdk';
const stealthPrivateKey = deriveStealthPrivateKey(
keys.viewingPrivateKey,
keys.spendingPrivateKey,
payment.ephemeralPubKey
);
// Use stealthPrivateKey to spend from the stealth addressimport { generateRingSignature } from '@grimswap/sdk';
const { signature, keyImage } = generateRingSignature({
message: messageHash,
privateKey: yourPrivateKey,
publicKeys: ringMembers, // Array of addresses (you + decoys)
signerIndex: yourIndex, // Your position in the ring
});| Function | Description |
|---|---|
generateStealthKeys() |
Generate spending/viewing key pairs |
generateStealthAddress(metaAddress) |
Generate one-time stealth address |
checkStealthAddress(...) |
Check if a stealth address belongs to you |
deriveStealthPrivateKey(...) |
Derive private key for spending |
parseMetaAddress(metaAddress) |
Parse meta-address components |
createMetaAddress(spending, viewing) |
Create meta-address from keys |
| Function | Description |
|---|---|
generateRingSignature(params) |
Generate LSAG ring signature |
generateKeyImage(privateKey) |
Generate key image (prevents double-spend) |
verifyRingSignature(...) |
Verify ring signature (for testing) |
| Function | Description |
|---|---|
scanAnnouncements(params) |
Scan for stealth payments |
watchAnnouncements(...) |
Continuously watch for payments |
| Function | Description |
|---|---|
executePrivateSwap(...) |
Execute a private swap (WIP) |
encodeHookData(...) |
Encode data for GrimHook |
getRingMembers(...) |
Get decoy addresses for ring |
isKeyImageUsed(...) |
Check if key image is spent |
getTotalPrivateSwaps(...) |
Get protocol statistics |
| Export | Description |
|---|---|
UNICHAIN_SEPOLIA |
Testnet chain config |
UNICHAIN_MAINNET |
Mainnet chain config |
getChainConfig(chainId) |
Get config by chain ID |
*_ABI |
Contract ABIs |
| Contract | Address |
|---|---|
| GrimHook | 0xA4D8EcabC2597271DDd436757b6349Ef412B80c4 |
| RingVerifierMock | 0x6A150E2681dEeb16C2e9C446572087e3da32981E |
| StealthRegistry | 0xA9e4ED4183b3B3cC364cF82dA7982D5ABE956307 |
| Announcer | 0x42013A72753F6EC28e27582D4cDb8425b44fd311 |
| PoolTestHelper | 0x26a669aC1e5343a50260490eC0C1be21f9818b17 |
- All cryptographic operations run client-side
- Private keys never leave the browser
- Uses audited
@noble/curvesand@noble/hasheslibraries - Ring signatures provide k-anonymity (1-of-N)
- Stealth addresses are unlinkable to main wallet
MIT