Register Signer
How to register a signer for API authentication
Authentication: Register Signer
Before making any authenticated API calls, you need to register a signer. The signer is a private key that will be used to sign transactions on behalf of your account.
Step 1: Generate Signer Key
// Generate a new private key for the signer
const signingKey = generatePrivateKey();
const signerAccount = privateKeyToAccount(signingKey);
const signerAddress = signerAccount.address; // This is your signer addressStep 2: Create Account Signature (User Wallet Signature)
The account owner signs a RegisterSigner EIP-712 message authorizing the signer. The nonce system uses a
bitmap-based approach with nonceAnchor (epoch) and nonceBitmap (bit index) for replay protection.
const createAccountSignature = async (
signerAddress: `0x${string}`,
nonceAnchor: bigint, // uint48 nonce epoch anchor
nonceBitmap: number, // uint8 bit index within nonce bitmap
authContractAddress: `0x${string}`,
// You'll need a wallet provider (like wagmi, ethers, etc.)
signTypedDataAsync: (data: any) => Promise<string>,
) => {
const expiration = dayjs().add(7, 'day').unix(); // 7 days from now
const registerMessage = {
signer: signerAddress,
message: 'Please sign in with your wallet to access RISEx.',
expiration,
nonceAnchor,
nonceBitmap,
};
const domain = getRISExDomain(authContractAddress);
// User signs with their wallet
const accountSignature = await signTypedDataAsync({
types: REGISTER_TYPES,
message: {
signer: registerMessage.signer,
message: registerMessage.message,
expiration: registerMessage.expiration,
nonceAnchor: registerMessage.nonceAnchor,
nonceBitmap: registerMessage.nonceBitmap,
},
primaryType: 'RegisterSigner',
domain: domain as any,
});
return {
accountSignature,
registerMessage,
};
};Step 3: Register Signer via API
const registerSigner = async (
account: `0x${string}`,
authContractAddress: `0x${string}`,
nonceAnchor: bigint,
nonceBitmap: number,
signTypedDataAsync: (data: any) => Promise<string>,
) => {
try {
// Step 1: Generate signer key
const signingKey = generatePrivateKey();
const signerAccount = privateKeyToAccount(signingKey);
const signerAddress = signerAccount.address;
// Step 2: Get user wallet signature
const { accountSignature, registerMessage } = await createAccountSignature(
signerAddress as `0x${string}`,
nonceAnchor,
nonceBitmap,
authContractAddress,
signTypedDataAsync,
);
// Step 3: Register via API
const response = await apiClient.post('/v1/auth/register-signer', {
account: account,
signer: registerMessage.signer,
message: registerMessage.message,
nonce_anchor: nonceAnchor.toString(),
nonce_bitmap: nonceBitmap,
expiration: registerMessage.expiration.toString(),
account_signature: accountSignature,
});
if (response.data) {
console.log('Signer registered successfully:', {
account,
signer: signerAddress,
signingKey, // Store this securely!
expiration: registerMessage.expiration,
});
// IMPORTANT: Store signingKey securely for future API calls
return {
signer: signerAddress,
signingKey, // Keep this secret!
};
}
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Failed to register signer:', error.response?.data?.message || error.message);
} else {
console.error('Failed to register signer:', error);
}
throw error;
}
};Important Notes
- One-time setup: Register signer once per account
- Store securely: Keep the
signingKeyprivate and secure - it authorizes all transactions - Expiration: Signers expire after the expiration time (typically 7 days)
- Re-registration: You may need to re-register if the signer expires
- No signer signature required: Only the account owner's signature is needed to register a signer
- Permissions: Signers are granted
Permission.Allby default. UseenablePermission/disablePermissionon the authorization contract to manage granular permissions (Perps, Spot, MoveFund)