Predicting Wallet Addresses
Predict wallet addresses before deployment using the MSA API's deterministic address generation.
The MSA API allows you to predict wallet addresses before they're deployed. This is essential for funding wallets before creation and ensuring deterministic address generation.
Overview
MSA uses CREATE3 for deterministic address generation. Given a salt value, you can always calculate the exact wallet address that will be created, regardless of when or where the wallet is deployed.
How Address Prediction Works
The prediction algorithm:
- Takes your salt - Any string identifier
- Hashes the salt - Creates a unique hash
- Combines with factory and bytecode - Uses CREATE3 pattern
- Returns deterministic address - Same salt = same address
// Same salt always produces same address
const address1 = await client.predictWallet({ salt: 'user@example.com' });
const address2 = await client.predictWallet({ salt: 'user@example.com' });
console.log(address1.wallet === address2.wallet); // trueBasic Prediction
Single Address Prediction
// Using API HTTP (fetch)
const response = await fetch('https://api.msa.omnes.tech/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
accounts: [{
walletCustody: 1, // ECDSA_VALIDATOR
salt: 'user@example.com'
}],
settings: {
rpc: 'https://rpc-amoy.polygon.technology/',
factory: '0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4',
validator: '0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a',
entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789',
beaconAdminAddress: '0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618'
}
})
});
const result = await response.json();
const prediction = result.predictions[0];
console.log('Predicted address:', prediction.wallet);
console.log('Salt:', prediction.salt);
console.log('Custody type:', prediction.walletCustody);import requests
def predict_wallet():
url = "https://api.msa.omnes.tech/predict"
payload = {
"accounts": [{
"walletCustody": 1, # ECDSA_VALIDATOR
"salt": "user@example.com"
}],
"settings": {
"rpc": "https://rpc-amoy.polygon.technology/",
"factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
"validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
"entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618"
}
}
response = requests.post(url, json=payload)
result = response.json()
wallet_address = result['predictions'][0]['wallet']
print(f'Predicted wallet address: {wallet_address}')
return wallet_address
predict_wallet()curl -X POST "https://api.msa.omnes.tech/predict" \
-H "Content-Type: application/json" \
-d '{
"accounts": [{
"walletCustody": 1,
"salt": "user@example.com"
}],
"settings": {
"rpc": "https://rpc-amoy.polygon.technology/",
"factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
"validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
"entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618"
}
}'Expected Response:
{
"predictions": [{
"wallet": "0x28097eF2268B553783D9c32A33ECb1bB78B209F3",
"salt": "user@example.com",
"walletCustody": 1
}]
}Batch Prediction
Predict multiple addresses at once:
const predictions = await client.predictWallets([
{
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: 'user1@example.com'
},
{
walletCustody: CustodyType.PASSKEY_VALIDATOR,
salt: 'user2@example.com',
passkeyPubKey: ['base64-key']
},
{
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'org@example.com',
signers: ['0x...', '0x...'],
threshold: '2'
}
]);
predictions.forEach((pred, i) => {
console.log(`Wallet ${i + 1}:`, pred.wallet);
});Complete Workflow: Predict โ Fund โ Create
async function createWalletWithFunding() {
const salt = 'user@example.com';
// 1. Predict wallet address
console.log('๐ฎ Predicting wallet address...');
const prediction = await client.predictWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt
});
const walletAddress = prediction.wallet;
console.log(`โ
Predicted address: ${walletAddress}`);
// 2. Fund the wallet (using your preferred method)
console.log('๐ฐ Funding wallet...');
// Example: Send 0.1 MATIC to predicted address
// await sendTokens(walletAddress, '0.1');
// Or use a faucet on testnet
// 3. Create the wallet
console.log('๐๏ธ Creating wallet...');
const result = await client.createWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt
});
console.log(`โ
Wallet created! Tx: ${result.txHash}`);
console.log(`โ
Wallet address: ${walletAddress}`);
console.log(`โ
Address matches: ${result.wallet === walletAddress}`);
return { walletAddress, txHash: result.txHash };
}Using SmartWallet SDK
With the SmartWallet SDK, you can predict addresses locally:
import { SmartWallet, PKSigner } from '@omnes/smartwallet-ts-sdk';
const signer = await PKSigner.create(privateKey as `0x${string}`);
const smartWallet = await SmartWallet.create(
signer.signMessage,
signer.signMessage,
signer.getEVMAddress(),
rpcURL,
apiKey
);
// Predict address using SDK method
const salt = 'user@example.com';
const predictedAddress = smartWallet.predictWalletAddress(salt);
console.log('Predicted address:', predictedAddress);Salt Guidelines
Best Practices
-
Use Unique Identifiers
// Good salt: `user-${userId}` salt: `org-${organizationId}-wallet-1` salt: `${domain}-${userEmail}` // Avoid salt: 'wallet' // Too generic salt: '1' // Too simple -
Make It Meaningful
// Good - Easy to identify salt: `user-${userId}-main-wallet` salt: `${serviceName}-${userId}` // Good - Versioned salt: `${userId}-v1` salt: `${userId}-v2` -
Keep It Consistent
// Use same salt format across your application const generateSalt = (userId: string) => { return `user-${userId}-wallet`; };
Salt Examples
// User ID-based
salt: 'user-12345'
// Email-based
salt: 'user@example.com'
// UUID-based
salt: '550e8400-e29b-41d4-a716-446655440000'
// Composite
salt: 'org-456-user-123-main'
// Versioned
salt: 'user-123-v1'
salt: 'user-123-v2'Custody Type Considerations
Different custody types may require additional parameters:
Passkey Wallets
const prediction = await client.predictWallet({
walletCustody: CustodyType.PASSKEY_VALIDATOR,
salt: 'passkey-user@example.com',
passkeyPubKey: ['base64-url-encoded-public-key'] // Required
});Multisig Wallets
const prediction = await client.predictWallet({
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'multisig-org@example.com',
signers: ['0x...', '0x...', '0x...'],
threshold: '2'
});Verification
After creating a wallet, verify the address matches:
// Before creation
const prediction = await client.predictWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: 'user@example.com'
});
// After creation
const createResult = await client.createWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: 'user@example.com'
});
// Verify match
const addressesMatch = prediction.wallet.toLowerCase() ===
createResult.wallet.toLowerCase();
console.log('Addresses match:', addressesMatch); // Should be trueUse Cases
1. Pre-funding Wallets
// Predict address
const prediction = await client.predictWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: 'user@example.com'
});
// Fund before creation
await fundWallet(prediction.wallet, '0.1');
// Create wallet (now has funds)
await client.createWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: 'user@example.com'
});2. Wallet Lookup
// User provides email
const userEmail = 'user@example.com';
// Predict their wallet address
const prediction = await client.predictWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: userEmail
});
// Check if wallet exists
const check = await client.checkWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: userEmail
});
if (check.exists) {
console.log('User wallet:', check.wallet);
} else {
console.log('User wallet not created yet');
}3. Batch Wallet Preparation
// Predict addresses for multiple users
const users = ['user1@example.com', 'user2@example.com', 'user3@example.com'];
const predictions = await Promise.all(
users.map(email =>
client.predictWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: email
})
)
);
// Fund all wallets
await Promise.all(
predictions.map(pred => fundWallet(pred.wallet, '0.1'))
);
// Create all wallets
await client.createWallets(
users.map(email => ({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: email
}))
);Error Handling
try {
const prediction = await client.predictWallet({
walletCustody: CustodyType.ECDSA_VALIDATOR,
salt: 'user@example.com'
});
console.log('Prediction successful:', prediction.wallet);
} catch (error) {
if (error.message.includes('Invalid settings')) {
console.error('Check your factory and validator addresses');
} else if (error.message.includes('network')) {
console.error('Network connection failed');
} else {
console.error('Prediction failed:', error.message);
}
}Next Steps
- Creating Wallets - Deploy your predicted wallets
- Checking Wallets - Verify wallet existence
- Custody Types - Understand different wallet configurations
- Quick Start Guide - Complete wallet creation workflow
๐ก Pro Tip: Always predict wallet addresses before creating them. This allows you to pre-fund wallets, verify addresses, and ensure deterministic behavior across deployments.