Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
Function Signature
delegatedSignTransaction(
client: DelegatedEvmWalletClient,
params: {
walletId: string;
walletApiKey: string;
keyShare: ServerKeyShare;
transaction: TransactionSerializable;
}
): Promise<string>
Description
Signs an EVM transaction on behalf of a user who has granted delegation permission. This function requires delegation credentials (wallet ID, wallet API key, and key share) that are provided to your webhook endpoint when a user approves delegation.
The function serializes the transaction, signs it using MPC, and returns a fully signed transaction ready for broadcast.
Parameters
Required Parameters
client (DelegatedEvmWalletClient) - The delegated client instance created with createDelegatedEvmWalletClient()
walletId (string) - The wallet ID from the delegation webhook
walletApiKey (string) - The wallet-specific API key from the delegation webhook
keyShare (ServerKeyShare) - The server key share from the delegation webhook
transaction (TransactionSerializable) - The transaction object to sign (must be a valid Viem transaction)
Returns
Promise<string> - A hex-encoded signed transaction ready for broadcast
Example
Basic Transaction Signing
import {
createDelegatedEvmWalletClient,
delegatedSignTransaction
} from '@dynamic-labs-wallet/node-evm';
import type { TransactionSerializable } from 'viem';
const delegatedClient = createDelegatedEvmWalletClient({
environmentId: 'your-environment-id',
apiKey: 'your-server-api-key',
});
const transaction: TransactionSerializable = {
to: '0xRecipientAddress',
value: BigInt('1000000000000000000'), // 1 ETH
chainId: 1,
nonce: 0,
gasLimit: BigInt('21000'),
maxFeePerGas: BigInt('20000000000'),
maxPriorityFeePerGas: BigInt('1000000000'),
};
const signedTx = await delegatedSignTransaction(delegatedClient, {
walletId: 'wallet-id-from-webhook',
walletApiKey: 'wallet-api-key-from-webhook',
keyShare: keyShareFromWebhook,
transaction,
});
console.log('Signed transaction:', signedTx);
Complete Flow with Broadcasting
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
async function sendDelegatedTransaction(
credentials: DelegationCredentials,
to: string,
value: bigint
) {
const fromAddress = await getWalletAddress(credentials.walletId);
const nonce = await publicClient.getTransactionCount({
address: fromAddress,
});
const gasEstimate = await publicClient.estimateGas({
account: fromAddress,
to,
value,
});
const feeData = await publicClient.estimateFeesPerGas();
const transaction: TransactionSerializable = {
to,
value,
chainId: mainnet.id,
nonce,
gasLimit: gasEstimate,
maxFeePerGas: feeData.maxFeePerGas!,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas!,
};
const signedTx = await delegatedSignTransaction(delegatedClient, {
walletId: credentials.walletId,
walletApiKey: credentials.walletApiKey,
keyShare: credentials.keyShare,
transaction,
});
const txHash = await publicClient.sendRawTransaction({
serializedTransaction: signedTx as `0x${string}`,
});
return txHash;
}
EIP-1559 Transaction
const transaction: TransactionSerializable = {
to: '0xRecipientAddress',
value: BigInt('1000000000000000000'),
chainId: 1,
nonce: 5,
gasLimit: BigInt('21000'),
maxFeePerGas: BigInt('50000000000'), // 50 gwei (important-comment)
maxPriorityFeePerGas: BigInt('2000000000'), // 2 gwei (important-comment)
type: 'eip1559',
};
const signedTx = await delegatedSignTransaction(delegatedClient, {
walletId: credentials.walletId,
walletApiKey: credentials.walletApiKey,
keyShare: credentials.keyShare,
transaction,
});
Contract Interaction
import { encodeFunctionData } from 'viem';
const data = encodeFunctionData({
abi: contractAbi,
functionName: 'transfer',
args: [recipientAddress, amount],
});
const transaction: TransactionSerializable = {
to: contractAddress,
data,
value: BigInt(0),
chainId: 1,
nonce: 10,
gasLimit: BigInt('100000'),
maxFeePerGas: BigInt('30000000000'),
maxPriorityFeePerGas: BigInt('1500000000'),
};
const signedTx = await delegatedSignTransaction(delegatedClient, {
walletId: credentials.walletId,
walletApiKey: credentials.walletApiKey,
keyShare: credentials.keyShare,
transaction,
});
Type Definitions
type ServerKeyShare = {
pubkey: {
pubkey: Uint8Array;
};
secretShare: string;
};
type TransactionSerializable = {
to?: `0x${string}`;
from?: `0x${string}`;
nonce?: number;
value?: bigint;
data?: `0x${string}`;
gasLimit?: bigint;
gasPrice?: bigint;
maxFeePerGas?: bigint;
maxPriorityFeePerGas?: bigint;
chainId?: number;
type?: 'legacy' | 'eip1559' | 'eip2930';
accessList?: any[];
};
Common Use Cases
Automated Payments
async function processAutomatedPayment(
userId: string,
recipient: string,
amount: bigint
): Promise<string> {
const credentials = await getDelegationCredentials(userId);
const walletAddress = await getWalletAddress(credentials.walletId);
const nonce = await publicClient.getTransactionCount({
address: walletAddress,
});
const transaction: TransactionSerializable = {
to: recipient,
value: amount,
chainId: 1,
nonce,
gasLimit: BigInt('21000'),
maxFeePerGas: BigInt('20000000000'),
maxPriorityFeePerGas: BigInt('1000000000'),
};
const signedTx = await delegatedSignTransaction(delegatedClient, {
walletId: credentials.walletId,
walletApiKey: credentials.walletApiKey,
keyShare: credentials.keyShare,
transaction,
});
return await publicClient.sendRawTransaction({
serializedTransaction: signedTx as `0x${string}`,
});
}
Batch Transactions
async function processBatchTransactions(
userId: string,
transactions: Array<{ to: string; value: bigint }>
): Promise<string[]> {
const credentials = await getDelegationCredentials(userId);
const walletAddress = await getWalletAddress(credentials.walletId);
let nonce = await publicClient.getTransactionCount({
address: walletAddress,
});
const txHashes: string[] = [];
for (const tx of transactions) {
const transaction: TransactionSerializable = {
to: tx.to,
value: tx.value,
chainId: 1,
nonce: nonce++,
gasLimit: BigInt('21000'),
maxFeePerGas: BigInt('20000000000'),
maxPriorityFeePerGas: BigInt('1000000000'),
};
const signedTx = await delegatedSignTransaction(delegatedClient, {
walletId: credentials.walletId,
walletApiKey: credentials.walletApiKey,
keyShare: credentials.keyShare,
transaction,
});
const txHash = await publicClient.sendRawTransaction({
serializedTransaction: signedTx as `0x${string}`,
});
txHashes.push(txHash);
}
return txHashes;
}
Error Handling
The function throws an error if:
- Any required parameter is missing or invalid
- The transaction object is malformed
- The delegation credentials are expired or revoked
- The MPC signing operation fails
- Transaction serialization fails
try {
const signedTx = await delegatedSignTransaction(delegatedClient, params);
console.log('Transaction signed successfully');
} catch (error) {
if (error.message.includes('serialized')) {
console.error('Invalid transaction format');
} else if (error.message.includes('key share')) {
console.error('Invalid or expired delegation credentials');
} else {
console.error('Signing failed:', error);
}
throw error;
}
Security Considerations
- Transaction Validation: Always validate transaction parameters before signing
- Gas Limits: Set appropriate gas limits to prevent excessive gas consumption
- Amount Validation: Validate transaction amounts to prevent unauthorized transfers
- Recipient Validation: Verify recipient addresses are correct and trusted
- Nonce Management: Properly manage nonces to prevent transaction conflicts
- Audit Logging: Log all transaction signing operations
delegatedSignTypedData
Function Signature
delegatedSignTypedData(
client: DelegatedEvmWalletClient,
params: {
walletId: string;
walletApiKey: string;
keyShare: ServerKeyShare;
typedData: TypedData;
}
): Promise<string>
Description
Signs EIP-712 typed data on behalf of a user who has granted delegation permission. This function requires delegation credentials (wallet ID, wallet API key, and key share) that are provided to your webhook endpoint when a user approves delegation.
Use this for permit flows, order signing, and other structured data that requires typed-data signing.
Parameters
Required Parameters
client (DelegatedEvmWalletClient) - The delegated client instance created with createDelegatedEvmWalletClient()
walletId (string) - The wallet ID from the delegation webhook
walletApiKey (string) - The wallet-specific API key from the delegation webhook
keyShare (ServerKeyShare) - The server key share from the delegation webhook
typedData (TypedData) - The EIP-712 typed data to sign (viem’s TypedData type)
Returns
Promise<string> - A hex-encoded ECDSA signature
Example
import {
createDelegatedEvmWalletClient,
delegatedSignTypedData
} from '@dynamic-labs-wallet/node-evm';
import type { TypedData } from 'viem';
const delegatedClient = createDelegatedEvmWalletClient({
environmentId: 'your-environment-id',
apiKey: 'your-server-api-key',
});
const typedData: TypedData = {
domain: {
name: 'USD Coin',
version: '2',
chainId: 1,
verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
},
types: {
Permit: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
primaryType: 'Permit',
message: {
owner: '0xOwnerAddress',
spender: '0xSpenderAddress',
value: BigInt('1000000'), // 1 USDC (6 decimals)
nonce: BigInt(0),
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour from now
},
};
const signature = await delegatedSignTypedData(delegatedClient, {
walletId: 'wallet-id-from-webhook',
walletApiKey: 'wallet-api-key-from-webhook',
keyShare: keyShareFromWebhook,
typedData,
});
console.log('Signature:', signature);
Security Considerations
- Data Validation: Always validate typed data structure before signing
- Domain Verification: Verify the domain matches the expected contract
- Expiry Times: Set appropriate deadlines to prevent replay attacks
- Nonce Management: Properly track and increment nonces
- Contract Verification: Ensure verifyingContract addresses are correct
- Audit Logging: Log all typed data signing operations