@getsafle/unified-id-sdk
v1.0.3
Published
JavaScript SDK for Unified ID registration and management
Readme
Unified ID SDK
A functional JavaScript SDK for Unified ID registration and management.
Features
- 📝 Unified ID Registration: Register new unified IDs with cryptographic signatures
- 🔗 Secondary Address Management: Add and remove secondary addresses
- ⚡ Class-based Design: Easy-to-use UnifiedIdSDK class
- 🔒 Security: EIP-191 compliant signatures and secure nonce management
- 🔍 Comprehensive Utility Functions: Check contract states, validate addresses, and verify data
Installation
npm install unified-id-sdkQuick Integration Checklist
- Initialize the SDK with config (see below)
- Use SDK utility functions for nonce and signature hash
- Sign the hash with your wallet or signing method
- Call the SDK class methods for API actions
SDK Initialization
You must provide all config values explicitly. There are no defaults or environment variable fallbacks. The contract address is set automatically based on environment and chainId.
const UnifiedIdSDK = require('unified-id-sdk');
const config = {
baseURL: 'safle_api_base_url', // API base URL (required)
authToken: 'your-bearer-token-here', // Auth token (required)
chainId: 11155111, // Blockchain chain ID (required, e.g. Sepolia)
environment: 'testnet' // 'testnet' or 'mainnet' (required)
};
const sdk = new UnifiedIdSDK(config);If any config value is missing or invalid, the SDK will throw an error.
Environment and Chain ID Validation
environmentmust be either'testnet'or'mainnet'.- The
chainIdmust match the allowed values for the selected environment. - The contract address is set automatically; do not provide it manually.
Usage Examples
Note: For all flows, you must sign the hash returned by createSignatureMessage using your preferred wallet or signing method (e.g., MetaMask, ethers.js, hardware wallet, etc.).
1. Register a New Unified ID
Step 1: Generate the signature hash
const { getNonce, createSignatureMessage } = require('unified-id-sdk');
const nonce = await getNonce('my-unified-id', config, 'https://sepolia.infura.io/v3/YOUR_PROJECT_ID');
const hash = createSignatureMessage('register', {
unifiedId: 'my-unified-id',
userAddress: '0xUSER_ADDRESS',
nonce: Number(nonce)
});Step 2: Sign the hash
- Dapp/user must sign the hash using their wallet.
Step 3: Call the SDK method
const result = await sdk.registerUnifiedId({
unifiedId: 'my-unified-id',
userAddress: '0xUSER_ADDRESS',
nonce: Number(nonce),
signature // <- the signature from the user
});2. Add a Secondary Address
Step 1: Generate the signature hash
const nonce = await getNonce('my-unified-id', config, 'https://sepolia.infura.io/v3/YOUR_PROJECT_ID');
const hash = createSignatureMessage('register', {
unifiedId: 'my-unified-id',
userAddress: '0xSECONDARY_ADDRESS',
nonce: Number(nonce)
});Step 2: Sign the hash
- Both the primary and secondary wallets must sign the hash.
- Pass both signatures to the SDK method below.
Step 3: Call the SDK method
const result = await sdk.addSecondaryAddress({
unifiedId: 'my-unified-id',
secondaryAddress: '0xSECONDARY_ADDRESS',
nonce: Number(nonce),
primarySignature, // <- signature from primary wallet
secondarySignature // <- signature from secondary wallet
});3. Remove a Secondary Address
Step 1: Generate the signature hash
const nonce = await getNonce('my-unified-id', config, 'https://sepolia.infura.io/v3/YOUR_PROJECT_ID');
const hash = createSignatureMessage('removeSecondary', {
unifiedId: 'my-unified-id',
secondaryAddress: '0xSECONDARY_ADDRESS',
nonce: Number(nonce)
});Step 2: Sign the hash
- The primary wallet must sign the hash.
Step 3: Call the SDK method
const result = await sdk.removeSecondaryAddress({
unifiedId: 'my-unified-id',
secondaryAddress: '0xSECONDARY_ADDRESS',
nonce: Number(nonce),
signature // <- signature from primary wallet
});4. Update Unified ID
Step 1: Generate the signature hash
const nonce = await getNonce('old-unified-id', config, 'https://sepolia.infura.io/v3/YOUR_PROJECT_ID');
const hash = createSignatureMessage('updateUnifiedId', {
oldUnifiedId: 'old-unified-id',
newUnifiedId: 'new-unified-id',
nonce: Number(nonce)
});Step 2: Sign the hash
- The primary wallet must sign the hash
Step 3: Call the SDK method
const result = await sdk.updateUnifiedId({
oldUnifiedId: 'old-unified-id',
newUnifiedId: 'new-unified-id',
nonce: Number(nonce),
signature // <- signature from primary wallet
});5. Change Primary Address
Step 1: Generate the signature hash
const nonce = await getNonce('my-unified-id', config, 'https://sepolia.infura.io/v3/YOUR_PROJECT_ID');
const hash = createSignatureMessage('primaryChange', {
unifiedId: 'my-unified-id',
newAddress: '0xNEW_PRIMARY_ADDRESS',
nonce: Number(nonce)
});Step 2: Sign the hash
- Both the current and new primary wallets must sign the hash.
- Pass both signatures to the SDK method below.
Step 3: Call the SDK method
const result = await sdk.changePrimaryAddress({
unifiedId: 'my-unified-id',
newAddress: '0xNEW_PRIMARY_ADDRESS',
nonce: Number(nonce),
currentPrimarySignature, // <- signature from current primary wallet
newPrimarySignature // <- signature from new primary wallet
});Utility Functions
The SDK provides comprehensive utility functions for checking contract states, validating addresses, and verifying data. These functions can be used both as SDK instance methods and as direct exports.
Core Utility Functions
You can use these functions directly:
const {
getProvider,
getNonce,
createSignatureMessage,
createOptions,
// Contract state utilities
isValidUnifiedID,
isPrimaryAddressAlreadyRegistered,
isSecondaryAddressAlreadyRegistered,
isUnifiedIDAlreadyRegistered,
getMasterWalletforUnifiedID,
getPrimaryWalletforUnifiedID,
getSecondaryWalletsforUnifiedID,
getUnifiedIDByPrimaryAddress,
getRegistrationFees,
validateSignature
} = require('unified-id-sdk');SDK Instance Methods
When using the SDK class, you can call utility functions as instance methods:
const sdk = new UnifiedIdSDK(config);
// Check if unified ID is valid
const isValid = await sdk.isValidUnifiedID('example.id', rpcUrl);
console.log('Is valid:', isValid);
// Check if address is registered as primary
const isPrimary = await sdk.isPrimaryAddressAlreadyRegistered('0xPRIMARY_ADDRESS', rpcUrl);
console.log('Is primary:', isPrimary);
// Check if address is registered as secondary
const isSecondary = await sdk.isSecondaryAddressAlreadyRegistered('0xSECONDARY_ADDRESS',rpcUrl);
console.log('Is secondary:', isSecondary);
// Check if unified ID is already registered
const isRegistered = await sdk.isUnifiedIDAlreadyRegistered('example.id', rpcUrl);
console.log('Is registered:', isRegistered);
// Get master wallet for unified ID
const masterWallet = await sdk.getMasterWalletforUnifiedID('example.id', rpcUrl);
console.log('Master wallet:', masterWallet);
// Get primary wallet for unified ID
const primaryWallet = await sdk.getPrimaryWalletforUnifiedID('example.id', rpcUrl);
console.log('Primary wallet:', primaryWallet);
// Get secondary wallets for unified ID
const secondaryWallets = await sdk.getSecondaryWalletsforUnifiedID('example.id', rpcUrl);
console.log('Secondary wallets:', secondaryWallets);
// Get unified ID by primary address
const unifiedId = await sdk.getUnifiedIDByPrimaryAddress('0xPRIMARY_ADDRESS', chainId, rpcUrl);
console.log('Unified ID:', unifiedId);
// Get registration fees for a token
const fees = await sdk.getRegistrationFees('TOKEN_ADDRESS', '1000000000000000000', rpcUrl);
console.log('Registration fees:', fees);
// Validate signature
const isValidSignature = await sdk.validateSignature(data, expectedSigner, signature, rpcUrl);
console.log('Signature valid:', isValidSignature);Example Use Cases
Pre-validation before registration
// Check if unified ID already exists before attempting registration
const isValid = await sdk.isValidUnifiedID(unifiedId, rpcUrl);
const isRegistered = await sdk.isUnifiedIDAlreadyRegistered(unifiedId, rpcUrl);
if (!isValid || isRegistered) {
console.log('Unified ID is invalid or already registered');
return;
}
// Proceed with registrationAddress validation
// Check if address is available before adding as secondary
const isPrimary = await sdk.isPrimaryAddressAlreadyRegistered(address, rpcUrl);
const isSecondary = await sdk.isSecondaryAddressAlreadyRegistered(address, rpcUrl);
if (isPrimary || isSecondary) {
console.log('Address is already registered');
return;
}
// Proceed with adding secondary addressWallet information retrieval
// Get all wallet information for a unified ID
const masterWallet = await sdk.getMasterWalletforUnifiedID(unifiedId, rpcUrl);
const primaryWallet = await sdk.getPrimaryWalletforUnifiedID(unifiedId, rpcUrl);
const secondaryWallets = await sdk.getSecondaryWalletsforUnifiedID(unifiedId, rpcUrl);
console.log('Master wallet:', masterWallet);
console.log('Primary wallet:', primaryWallet);
console.log('Secondary wallets:', secondaryWallets);Signature validation
// Validate a signature for a specific operation
const data = createSignatureMessage('register', {
unifiedId: 'example.id',
userAddress: 'USER_ADDRESS',
nonce: 1
});
const isValid = await sdk.validateSignature(data, expectedSigner, signature, rpcUrl);
console.log('Signature valid:', isValid);Error Handling
All SDK methods return a result object:
const result = await sdk.registerUnifiedId(params);
if (!result.success) {
console.error('Error:', result.error);
console.error('Details:', result.details);
}Utility functions throw descriptive errors when:
- Required parameters are missing
- Contract calls fail
- Network issues occur
- Invalid addresses are provided
Example error handling:
try {
const result = await sdk.isValidUnifiedID(unifiedId, rpcUrl);
console.log('Result:', result);
} catch (error) {
console.error('Error checking unified ID:', error.message);
}Security Considerations
- Private Keys: Never expose private keys in client-side code
- Network Security: Use HTTPS for all API communications
- Token Management: Store authentication tokens securely
- Nonce Management: The SDK provides utilities for nonce retrieval
- Signature Verification: All signatures follow EIP-191 standards
- Address Validation: Always validate addresses before using them in operations
License
MIT License - see LICENSE file for details.
Support
For support and questions, please open an issue on GitHub or contact the development team.
