FAQ
Frequently asked questions about Range
Verification Errors
Section titled “Verification Errors”Why am I getting 'CouldntVerifySignature'?
This error means the Ed25519 signature verification failed. Common causes:
- Wrong signing key: The keypair used to sign doesn’t match
range_signerin Settings - Message modified: The message was changed after signing
- Corrupted signature: Signature bytes were altered in transit
Solution: Verify your backend is using the correct keypair:
// Check that this matches Settings.range_signerconsole.log('Signing with:', rangeSignerKeypair.publicKey.toBase58());Why am I getting 'TimestampOutOfWindow'?
The timestamp in the message is outside the allowed time window. This happens when:
- Signature expired: Too much time passed between signing and verification
- Clock drift: Backend and Solana clocks are out of sync
- window_size too small: Not enough buffer for network latency
Solutions:
- Request a fresh signature and verify immediately
- Increase
window_sizein Settings (viaupdate_settings) - Ensure your backend server uses NTP for clock synchronization
Why am I getting 'WrongSigner'?
The pubkey in the signed message doesn’t match the transaction signer. This means:
- Wrong user: You’re trying to use someone else’s signature
- Message error: Backend signed with wrong pubkey in message
Solution: Ensure the message pubkey matches who’s signing the transaction:
// Message formatconst message = `${timestamp}_${transactionSigner.toBase58()}`;// ^ Must match who signs the txWhy am I getting 'WrongMessageSplitLength'?
The message format is incorrect. Expected format: {timestamp}_{pubkey}
Common mistakes:
- Missing underscore:
1704067200ABC123... - Extra underscores:
1704067200__ABC123... - Empty fields:
_ABC123...or1704067200_
Solution: Check your message construction:
const message = `${timestamp}_${pubkey.toBase58()}`; // Single underscoreConfiguration
Section titled “Configuration”What window_size should I use?
It depends on your use case:
| Use Case | Recommended | Rationale |
|---|---|---|
| Normal operations | 60 seconds | Good balance |
| High security | 30 seconds | Smaller replay window |
| Slow networks | 120 seconds | More latency tolerance |
Start with 60 seconds and adjust based on TimestampOutOfWindow error rates.
Can I change range_signer after deployment?
Yes, use update_settings:
const instruction = await buildUpdateSettingsInstruction({ admin: adminPublicKey, rangeSigner: newSignerPublicKey,});Can multiple admins share one Settings account?
No, each Settings account has exactly one admin. However, you can:
- Transfer admin to a multi-sig (e.g., Squads)
- Create separate Settings for each admin
- Implement your own access control on top
Architecture
Section titled “Architecture”Do I need Range.org to use Range?
No. Range.org is an optional compliance service. You can:
- Use any compliance service
- Implement your own compliance logic
- Skip compliance entirely (just use Range for signature verification)
The Range program only verifies signatures - it doesn’t know about Range.org.
What's the difference between verify_range and verify_range_with_callback?
| Instruction | Use Case |
|---|---|
verify_range | Just verify, no follow-up action |
verify_range_with_callback | Verify then call your program atomically |
Use callback when you need atomic operations - if your callback fails, the verification is also rolled back.
Can I call Range from my program (CPI)?
Yes, see the Build CPI Program guide. Your program can:
- Call
verify_rangevia CPI to add verification to your instructions - Implement
on_verifyto receive callbacks from Range
What happens if my callback fails?
The entire transaction reverts, including the Range verification. This is by design - it ensures atomicity. You can’t have a “verified but action failed” state.
Development
Section titled “Development”How do I generate TypeScript/Rust clients?
Use Codama to generate type-safe clients from the IDL:
anchor build # Generate IDLnpm run codama # Generate clientsSee Client Setup (Codama) for details.
Where can I find working code examples?
The best reference is the test file: tests/range.ts
It includes examples of:
- Settings initialization
- Message signing
- Verification (success and failure cases)
- CPI patterns
- Error handling
How do I test locally?
git clone https://github.com/ZKLSOL/range.gitcd rangeyarn installanchor testSee Testing Locally for details.
Is there a deployed program I can use?
Range is currently pre-deployment. You’ll need to deploy your own instance:
anchor buildanchor deploySave the program ID and update your clients accordingly.
Security
Section titled “Security”How do I protect my range_signer key?
- Never put it in client-side code
- Use secure key management (AWS KMS, HashiCorp Vault)
- Separate keys for devnet and mainnet
- Have a key rotation procedure ready
See Security for complete recommendations.
What if my range_signer key is compromised?
- Immediately call
update_settingsto rotate to a new key - Update your backend with the new signing key
- Audit recent transactions for suspicious activity
Having a key rotation procedure documented beforehand is critical.
Can someone replay my signature?
Only within the window_size period. After that, the timestamp check fails.
For extra protection:
- Keep
window_sizesmall - Use on-chain nonces for high-value operations
- Track used signatures in your backend
How do I prevent direct calls to my on_verify callback?
Always verify the CPI caller:
let calling_ix = get_instruction_relative(-1, ix_sysvar)?;require!( calling_ix.program_id == RANGE_PROGRAM_ID, ErrorCode::CpiOnly);Without this check, attackers could bypass Range verification entirely.
Troubleshooting
Section titled “Troubleshooting”My transaction keeps failing with 'account not found'
Ensure all required accounts are provided:
- Settings PDA: Derived from admin pubkey
- Instructions Sysvar:
SYSVAR_INSTRUCTIONS_PUBKEY - For callbacks: All
remaining_accountsin correct order
const [settingsPda] = PublicKey.findProgramAddressSync( [Buffer.from('settings'), adminPubkey.toBuffer()], RANGE_PROGRAM_ID);How do I debug verification failures?
Check transaction logs:
const tx = await connection.getTransaction(signature, { commitment: 'confirmed',});console.log('Logs:', tx?.meta?.logMessages);Common issues appear in logs as error messages.
The build is failing after updating Range
Regenerate clients after any IDL changes:
anchor buildnpm run codamaThen check if your code needs updates for any API changes.
Still Have Questions?
Section titled “Still Have Questions?”- Check the GitHub repository for latest updates
- Review the test suite for working examples
- Read the Architecture documentation for deeper understanding