Skip to Content
dApps
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 fieldPurpose
nameHuman-readable application or protocol name
versionVersion of the signing domain
chainIdChain for which the signature is intended
verifyingContractAddress of the contract that verifies the signature; this is an address, not a URL
saltOptional 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.

Example

Open example 

Last updated on