When using Privy’s server-side SDKs to sign typed data, you can use the authorization context to
automatically sign requests. Learn more about signing on the
server.
- React
- React Native
- Swift
- Android
- Unity
- Flutter
- NodeJS
- NodeJS (server-auth)
- Java
- Rust
- REST API
Use the
As parameters to
signTypedData method exported from the useSignTypedData hook to sign a message with an Ethereum embedded wallet.Report incorrect code
Copy
Ask AI
signTypedData(input: SignTypedDataParams, options?: SignTypedDataOptions): Promise<{signature: string}>
Usage
Report incorrect code
Copy
Ask AI
import {useSignTypedData, useWallets} from '@privy-io/react-auth';
const {signTypedData} = useSignTypedData();
const {wallets} = useWallets();
const {signature} = await signTypedData({...}, {
address: wallets[0].address // Optional: Specify the wallet to use for signing. If not provided, the first wallet will be used.
});
Parameters
The typed data object to sign with the wallet, with the properties defined in
EIP-712.
Hide properties
Hide properties
UI options to customize the signature prompt modal. Learn
more
To hide confirmation modals, set
options.uiOptions.showWalletUIs to false. Learn more
about configuring modal prompts here.Address of the wallet to use for signing the typed data. Recommended when working with
external wallets to ensure reliable functionality. If not provided, the first wallet will be
used.
Response
The signature produced by the wallet.
Callbacks
Configure callbacks forsignTypedData with the useSignTypedData hook.Report incorrect code
Copy
Ask AI
import {useSignTypedData} from '@privy-io/react-auth';
const {signTypedData} = useSignTypedData({
onSuccess: ({signature}) => {
console.log(signature);
// Any logic you'd like to execute after a user successfully signs the EIP-712 typed data
},
onError: (error) => {
console.log(error);
// Any logic you'd like to execute after a user exits the signing flow or there is an error
}
});
// Then call `signTypedData` in your code, which will invoke these callbacks on completion
useSignTypedData, you may include an onSuccess callback and/or an onError callback.While this component is mounted, any invocation of signTypedData will trigger the onSuccess callback or onError callback on completion, depending on if the data was successfully signed or not.onSuccess
If set, theonSuccess callback will execute after a user has successfully signed the message. Within this callback, you can access a signature parameter, which is the signature string value generated by the wallet to sign the data.onError
If set, theonError callback will execute after a user attempts to sign the typed data and there is an error, or if the user exits the signature flow prematurely. Within this callback, you may access an error code with more information about the error.Request a message signature on the wallets Ethereum provider.
Report incorrect code
Copy
Ask AI
request: ({method: 'eth_signTypedData_v4', params: [address, typedData]}) => Promise<{signature: string}>
The Expo SDK does not support built-in UIs for signing typed data. The
eth_signTypedData_v4
method gives you complete control over the experience and UI.Usage
Report incorrect code
Copy
Ask AI
import {useEmbeddedEthereumWallet} from '@privy-io/expo';
const {wallets} = useEmbeddedEthereumWallet();
const wallet = wallets[0];
// Get an EIP-1193 Provider
const provider = await wallet.getProvider();
// Get address
const accounts = await provider.request({
method: 'eth_requestAccounts'
});
const signature = await provider.request({
method: 'eth_signTypedData_v4',
params: [accounts[0], typedData]
});
Parameters
The method for the wallet request. For signing messages, this is
'eth_signTypedData_v4'.Returns
The signature produced by the wallet.
To request an EIP712 signature from a user’s embedded wallet, send an
eth_signTypedData_v4 JSON-RPC request to the wallet’s EIP1193 provider.Report incorrect code
Copy
Ask AI
struct Message: Encodable {
struct W: Encodable {
let name: String
let wallet: String
}
let from: W
let to: W
let contents: String
}
func typedData() async throws {
let wallets = user.embeddedEthereumWallets
// Grab the desired wallet. Here, we retrieve the first wallet
guard let wallet = wallets.first else {
// No ETH wallets
return
}
let typedData = EthereumRpcRequest.EIP712TypedData(
types: [
"EIP712Domain": [
.init("name", type: "string"),
.init("version", type: "string"),
.init("chainId", type: "uint256"),
.init("verifyingContract", type: "address"),
],
"Person": [
.init("name", type: "string"),
.init("wallet", type: "address"),
],
"Mail": [
.init("from", type: "Person"),
.init("to", type: "Person"),
.init("contents", type: "string"),
],
],
primaryType: "Mail",
domain: .init(
name: "Ether Mail",
version: "1",
chainId: 1,
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
),
message: Message(
from: Message.W(name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"),
to: Message.W(name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"),
contents: "Hello, Bob!"
)
)
let signature = try await provider.request(.ethSignTypedDataV4(address: wallet.address, typedData: typedData))
print(signature)
}
Parameters
The address of the wallet to sign the message with.
The typed data to sign with the wallet.
Hide child attributes
Hide child attributes
The types of the typed data, as defined by mapping the type names to
an array of
EIP712Type objects for each of its fields.Make sure to include the EIP712Domain type.The primary type of the typed data.
The domain of the typed data, per the EIP-712 specification.
Use the
EIP712Domain struct to define the domain.The message of the typed data.
This can be any struct that conforms to the
Encodable protocol.Returns
The signature produced by the wallet.
Report incorrect code
Copy
Ask AI
// Get Privy user
ethereumWallet.provider.request(
request = EthereumRpcRequest.ethSignTypedDataV4(ethereumWallet.address, typedData),
)
Parameters
The method for the wallet request. For signing messages, this is
'eth_signTypedData_v4'.Returns
The signature produced by the wallet.
Report incorrect code
Copy
Ask AI
try {
IEmbeddedEthereumWallet embeddedWallet = PrivyManager.Instance.User.EmbeddedWallets[0];
var rpcRequest = new RpcRequest
{m
Method = "eth_signTypedData_v4",
Params = new string[] {embeddedWallet.Address, typedData } // Use the 'new' keyword here
};
RpcResponse signTypedDataResponse = await embeddedWallet.RpcProvider.Request(rpcRequest);
Debug.Log(signTypedDataResponse.Data);
} catch (PrivyException.EmbeddedWalletException ex){
Debug.LogError($"Could not sign message due to error: {ex.Error} {ex.Message}");
} catch (Exception ex) {
Debug.LogError($"Could not sign message exception {ex.Message}");
}
Parameters
The method for the wallet request. For signing messages, this is
'eth_signTypedData_v4'.Returns
The signature produced by the wallet.
Report incorrect code
Copy
Ask AI
// Get an EIP-1193 Provider
final ethereumWallet = privy.user.embeddedEthereumWallets.first;
final provider = ethereumWallet.provider;
// Define the typed data
final typedData = {
'types': {
'EIP712Domain': [
{'name': 'name', 'type': 'string'},
{'name': 'version', 'type': 'string'},
{'name': 'chainId', 'type': 'uint256'},
{'name': 'verifyingContract', 'type': 'address'},
],
'Person': [
{'name': 'name', 'type': 'string'},
{'name': 'wallet', 'type': 'address'},
],
'Mail': [
{'name': 'from', 'type': 'Person'},
{'name': 'to', 'type': 'Person'},
{'name': 'contents', 'type': 'string'},
],
},
'primaryType': 'Mail',
'domain': {
'name': 'Ether Mail',
'version': '1',
'chainId': 1,
'verifyingContract': '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
'message': {
'from': {
'name': 'Cow',
'wallet': '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
'to': {
'name': 'Bob',
'wallet': '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
'contents': 'Hello, Bob!',
},
};
// Create the RPC request
final request = EthereumRpcRequest(
method: 'eth_signTypedData_v4',
params: [ethereumWallet.address, jsonEncode(typedData)],
);
// Sign the typed data
final result = await provider.request(request);
result.fold(
onSuccess: (response) {
final signature = response.data;
print('Signature: $signature');
},
onFailure: (error) {
print('Error signing typed data: ${error.message}');
},
);
Parameters
The method for the wallet request. For signing typed data, this is
'eth_signTypedData_v4'.Returns
The RPC method executed with the wallet.
Use the
signTypedData method on the Ethereum interface to sign a message with an Ethereum wallet.Usage
Report incorrect code
Copy
Ask AI
// Get the signature and encoding from the response
const {signature, encoding} = await privy
.wallets()
.ethereum()
.signTypedData('insert-wallet-id', {
params: {
typed_data: {
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
},
types: {
EIP712Domain: [
{name: 'name', type: 'string'},
{name: 'version', type: 'string'},
{name: 'chainId', type: 'uint256'},
{name: 'verifyingContract', type: 'address'}
],
Person: [
{name: 'name', type: 'string'},
{name: 'wallet', type: 'address'}
],
Mail: [
{name: 'from', type: 'Person'},
{name: 'to', type: 'Person'},
{name: 'contents', type: 'string'}
]
},
primary_type: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB'
},
contents: 'Hello, Bob!'
}
}
}
});
Parameters and Returns
Check out the API reference for more details.The
@privy-io/server-auth library is deprecated. We recommend integrating @privy-io/node for
the latest features and support.signTypedData method on the Ethereum client to sign a message with an Ethereum wallet.Report incorrect code
Copy
Ask AI
signTypedData: (input: {walletId: string, typedData: TypedData}) => Promise<{signature: string, encoding: 'hex'}>
Usage
Report incorrect code
Copy
Ask AI
// Get the signature and encoding from the response
const {signature, encoding} = await privy.walletApi.ethereum.signTypedData({
walletId: 'insert-wallet-id',
typedData: {
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
},
types: {
EIP712Domain: [
{name: 'name', type: 'string'},
{name: 'version', type: 'string'},
{name: 'chainId', type: 'uint256'},
{name: 'verifyingContract', type: 'address'}
],
Person: [
{name: 'name', type: 'string'},
{name: 'wallet', type: 'address'}
],
Mail: [
{name: 'from', type: 'Person'},
{name: 'to', type: 'Person'},
{name: 'contents', type: 'string'}
]
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB'
},
contents: 'Hello, Bob!'
}
}
});
Parameters
Unique ID of the wallet to take actions with.
Idempotency key to identify a unique request.
The typed data object to sign with the wallet, with the properties defined in
EIP-712.
Hide properties
Hide properties
Returns
An encoded string serializing the signature produced by the user’s wallet.
The encoding format for the returned
signature. Currently, only 'hex' is supported for
Ethereum.To sign typed data from your wallet, use the
signTypedData method.
It will sign your payload, and return the signature to you.Usage
Report incorrect code
Copy
Ask AI
try {
// Create typed data for EIP-712 signing
Map<String, Object> domain = Map.of(
"name", "Ether Mail",
"version", "1",
"chainId", 1,
"verifyingContract", "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
);
Map<String, List<EthereumSignTypedDataRpcInputType>> types = Map.of(
"EIP712Domain", List.of(
EthereumSignTypedDataRpcInputType.builder().name("name").type("string").build(),
EthereumSignTypedDataRpcInputType.builder().name("version").type("string").build(),
EthereumSignTypedDataRpcInputType.builder().name("chainId").type("uint256").build(),
EthereumSignTypedDataRpcInputType.builder().name("verifyingContract").type("address").build()
),
"Person", List.of(
EthereumSignTypedDataRpcInputType.builder().name("name").type("string").build(),
EthereumSignTypedDataRpcInputType.builder().name("wallet").type("address").build()
),
"Mail", List.of(
EthereumSignTypedDataRpcInputType.builder().name("from").type("Person").build(),
EthereumSignTypedDataRpcInputType.builder().name("to").type("Person").build(),
EthereumSignTypedDataRpcInputType.builder().name("contents").type("string").build()
)
);
Map<String, Object> message = Map.of(
"from", Map.of(
"name", "Cow",
"wallet", "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
),
"to", Map.of(
"name", "Bob",
"wallet", "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
),
"contents", "Hello, Bob!"
);
EthereumSignTypedDataRpcInputTypedData typedData = EthereumSignTypedDataRpcInputTypedData.builder()
.domain(domain)
.types(types)
.primaryType("TestMessage")
.message(message)
.build();
// Example: If wallet's owner is an authorization private key
AuthorizationContext authorizationContext = AuthorizationContext.builder()
.addAuthorizationPrivateKey("authorization-key")
.build();
EthereumSignTypedDataRpcResponseData response = privyClient
.wallets()
.ethereum()
.signTypedData(
walletId,
typedData,
authorizationContext
);
String signature = response.signature();
} catch (APIException e) {
String errorBody = e.bodyAsString();
System.err.println(errorBody);
} catch (Exception e) {
System.err.println(e.getMessage());
}
Parameters
When defining a typed data payload, you may specify the following values on theEthereumSignTypedDataRpcInputTypedData builder:The domain of the typed data payload.
The types of the typed data payload.
The message of the typed data payload.
The primary type of the typed data payload.
Returns
TheEthereumSignTypedDataRpcResponseData object contains a signature() fieldThe signature produced by the wallet.
Use the
sign_typed_data method on the Ethereum service to sign EIP-712 typed data with an Ethereum wallet.Usage
Report incorrect code
Copy
Ask AI
use privy_rs::{AuthorizationContext, PrivyClient};
let client = PrivyClient::new("app_id".to_string(), "app_secret".to_string())?;
let ethereum_service = client.wallets().ethereum();
let auth_ctx = AuthorizationContext::new();
// Create EIP-712 typed data structure
let typed_data = EthereumSignTypedDataRpcInputParamsTypedData {
domain: Default::default(),
message: Default::default(),
primary_type: "Mail".to_string(),
types: Default::default(),
};
let signature = ethereum_service
.sign_typed_data(&wallet_id, typed_data, &auth_ctx, None)
.await?;
println!("Typed data signed successfully");
Parameters and Returns
See the Rust SDK documentation for detailed parameter and return types, including embedded examples:For REST API details, see the API reference.To sign typed data make a POST request to
Report incorrect code
Copy
Ask AI
https://api.privy.io/v1/wallets/<wallet_id>/rpc
Parameters
RPC method to execute with the wallet.
Parameters for the RPC method to execute with the wallet.
Returns
The RPC method executed with the wallet.
Usage
Report incorrect code
Copy
Ask AI
curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
-u "<your-privy-app-id>:<your-privy-app-secret>" \
-H "privy-app-id: <your-privy-app-id>" \
-H "privy-authorization-signature: <authorization-signature-for-request>" \
-H 'Content-Type: application/json' \
-d '{
"method": "eth_signTypedData_v4",
"params": {
"typed_data": {
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallet", "type": "address" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person" },
{ "name": "contents", "type": "string" }
]
},
"message": {
"from": {
"name": "Alice",
"wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
},
"to": {
"name": "Bob",
"wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
},
"contents": "Hello, Bob!"
},
"primary_type": "Mail",
"domain": {
"name": "DApp Mail",
"version": "1",
"chainId": 1,
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
}
}
}
}'

