On this page
Signing Data
Use personal_sign for a human-readable message or eth_signTypedData_v4 for structured data described by EIP-712 . Request signatures after connecting an account, and explain what the user is authorizing before opening the wallet prompt.
Personal Messages
personal_sign takes the hex-encoded message first and the signer address second. The returned value is a signature string. A signature request does not submit a transaction or pay a network fee.
const provider = window.$onekey?.ethereum;
if (!provider) throw new Error('OneKey Ethereum provider is unavailable.');
const [address] = await provider.request({ method: 'eth_requestAccounts' });
const message = 'Sign in to example.com. Nonce: <SERVER_GENERATED_NONCE>';
const bytes = new TextEncoder().encode(message);
const data = '0x' + Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
try {
const signature = await provider.request({
method: 'personal_sign',
params: [data, address],
});
// Verify the signature and one-time challenge on your server.
console.log(signature);
} catch (error) {
console.error(error.code, error.message);
}For sign-in, replace the placeholder with a server-generated, single-use challenge and validate the intended domain, expiration, and signer. Never treat the existence of a signature as authentication without verification.
Typed Data v4
Call eth_signTypedData_v4 with [address, JSON.stringify(typedData)]. The typedData object contains types, primaryType, domain, and message. Each message field must match its declared type.
| Domain field | Purpose |
|---|---|
name | Human-readable application or protocol name |
version | Version of the signing domain |
chainId | Chain for which the signature is intended |
verifyingContract | Address of the contract that verifies the signature; this is an address, not a URL |
salt | Optional domain separator where required by the protocol |
Domain separation helps distinguish signing contexts. The verifying application or contract must still validate the domain and enforce its own replay protection; EIP-712 does not provide replay protection by itself.
// `typedData` must be built from your protocol's complete EIP-712 schema.
const signature = await provider.request({
method: 'eth_signTypedData_v4',
params: [address, JSON.stringify(typedData)],
});Legacy Signing Methods
Existing integrations may use eth_signTypedData or eth_signTypedData_v3. Their encodings differ from v4; changing the RPC method requires changing and testing the verifier as well. The RPC method names include the eth_ prefix.
Avoid eth_sign for application sign-in. It signs opaque data and can make the user’s intent difficult to verify. Method support can differ by account type, hardware model, firmware, and wallet version; handle unsupported-method errors instead of assuming every connected account can sign every format.