Repository navigation
API: Signer
The signer package provides isolated key management, session key lifecycle, delegation management, and enforcer mapping for AI agent wallets. Key material never touches the AI agent process.
npm install @wardexai/signerimport {
// Isolated process signer
SignerServer,
SignerClient,
encryptPrivateKey,
decryptPrivateKey,
generateApprovalToken,
verifyApprovalToken,
verifyAndConsumeApprovalToken,
generateConnectionAuthProof,
verifyConnectionAuthProof,
computeSerializedTransactionHash,
// Session keys (ERC-7715)
SessionManager,
// Session defaults
PRODUCTION_DEFAULTS,
createSessionWithDefaults,
// Delegation framework
DelegationManager,
// Enforcer mapping utilities
mapSessionConfigToCaveats,
getDefaultEnforcerAddresses,
encodeAllowedTargets,
encodeValueLte,
encodeTimestamp,
encodeNativeTokenPeriod,
encodeBlockedApprovalMethods,
decodeAllowedTargets,
decodeValueLte,
decodeTimestamp,
decodeNativeTokenPeriod,
} from '@wardexai/signer';The signer server runs in an isolated OS process and holds the encrypted private key. It listens on a Unix socket and only signs transactions that include a valid Wardex HMAC approval token. The AI agent process never has access to private key material.
import { SignerServer } from '@wardexai/signer';new SignerServer(config: SignerServerConfig)| Parameter | Type | Required | Description |
|---|---|---|---|
config.socketPath |
string |
Yes | Unix socket path for IPC communication. |
config.keyFilePath |
string |
Yes | Path to the AES-256-GCM encrypted key file. |
config.keyPassword |
string |
Yes | Password for key decryption (should come from an environment variable). |
config.sharedSecret |
string |
Yes | Shared HMAC secret between the SDK and signer for approval token verification. |
config.requireClientAuth |
boolean |
No | Require challenge-response auth for every socket connection. Default: true. |
config.maxConnections |
number |
No | Max simultaneous client connections. Default: 100. |
config.connectionRateLimitPerSecond |
number |
No | Max new connections per second. Default: 200. |
config.signFn |
(data: string, privateKey: string) => Promise<string> |
Yes | Pluggable signing function for different key types. |
config.getAddressFn |
(privateKey: string) => string |
Yes | Function that derives the public address from a private key. |
Starts the signer server: loads and decrypts the private key from disk, then begins listening on the Unix socket with restrictive permissions (0o600).
start(): Promise<void>const server = new SignerServer({
socketPath: '/tmp/wardex-signer.sock',
keyFilePath: '/secure/keyfile.json',
keyPassword: process.env.SIGNER_PASSWORD!,
sharedSecret: process.env.SIGNER_SECRET!,
signFn: async (data, pk) => { /* sign with secp256k1 */ },
getAddressFn: (pk) => { /* derive address */ },
});
await server.start();
console.log('Signer server running');Stops the signer server, zeroes out key material in memory, and removes the socket file.
stop(): Promise<void>await server.stop();The signer client is used by the agent process to communicate with the isolated signer server over a Unix socket. It has no access to key material.
import { SignerClient } from '@wardexai/signer';new SignerClient(config: SignerClientConfig)| Parameter | Type | Required | Description |
|---|---|---|---|
config.socketPath |
string |
Yes | Unix socket path to connect to. |
config.sharedSecret |
string |
No | Shared secret for connection challenge-response auth. Required if the server has requireClientAuth enabled (default). |
config.timeout |
number |
No | Request timeout in milliseconds. Default: 10000. |
Sends a transaction to the isolated signer for signing. Requires a valid HMAC approval token.
signTransaction(
serializedTx: string,
transactionHash: string,
approvalToken: string
): Promise<string>| Parameter | Type | Required | Description |
|---|---|---|---|
serializedTx |
string |
Yes | The serialized transaction data to sign. |
transactionHash |
string |
Yes | Hash of the transaction (used for approval token verification). |
approvalToken |
string |
Yes | HMAC-SHA256 approval token from generateApprovalToken. |
Promise<string> -- The signed transaction.
Throws Error if the signer rejects the request (invalid token, timeout, or connection failure).
Sends a message to the isolated signer for signing. Requires a valid HMAC approval token.
signMessage(
message: string,
approvalToken: string
): Promise<string>| Parameter | Type | Required | Description |
|---|---|---|---|
message |
string |
Yes | The message to sign. |
approvalToken |
string |
Yes | HMAC-SHA256 approval token. |
Promise<string> -- The message signature.
Requests the signer's public address from the isolated process.
getAddress(): Promise<string>Promise<string> -- The signer's Ethereum address.
Checks if the isolated signer process is available and responsive.
healthCheck(): Promise<boolean>Promise<boolean> -- true if the signer is healthy, false otherwise.
const client = new SignerClient({ socketPath: '/tmp/wardex-signer.sock' });
const healthy = await client.healthCheck();
if (!healthy) {
console.error('Signer process is not responding');
}Encrypts a private key for storage at rest using AES-256-GCM with scrypt key derivation.
import { encryptPrivateKey } from '@wardexai/signer';import { encryptPrivateKey } from '@wardexai/signer';
import fs from 'node:fs';
const encrypted = encryptPrivateKey(
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
'strong-password-from-env'
);
fs.writeFileSync('/secure/keyfile.json', JSON.stringify(encrypted));| Parameter | Type | Required | Description |
|---|---|---|---|
privateKey |
string |
Yes | The private key to encrypt. |
password |
string |
Yes | The password used to derive the encryption key via scrypt. |
interface EncryptedKeyFile {
version: 1;
algorithm: 'aes-256-gcm';
iv: string; // Hex-encoded 16-byte IV
authTag: string; // Hex-encoded GCM authentication tag
encryptedKey: string; // Hex-encoded ciphertext
salt: string; // Hex-encoded 32-byte scrypt salt
}Decrypts a private key from an encrypted key file.
import { decryptPrivateKey } from '@wardexai/signer';import { decryptPrivateKey } from '@wardexai/signer';
import fs from 'node:fs';
const keyFile = JSON.parse(fs.readFileSync('/secure/keyfile.json', 'utf8'));
const privateKey = decryptPrivateKey(keyFile, 'strong-password-from-env');| Parameter | Type | Required | Description |
|---|---|---|---|
keyFile |
EncryptedKeyFile |
Yes | The encrypted key file object (as produced by encryptPrivateKey). |
password |
string |
Yes | The password used during encryption. |
string -- The decrypted private key.
Throws if the password is incorrect or the data is tampered (GCM authentication failure).
Generates a cryptographic HMAC-SHA256 approval token that proves Wardex evaluated and approved a specific transaction. The token binds to both the transaction hash and a timestamp.
import { generateApprovalToken } from '@wardexai/signer';const token = generateApprovalToken(
'0xabc123...', // transaction hash
'shared-secret-between-sdk-and-signer'
);| Parameter | Type | Required | Description |
|---|---|---|---|
transactionHash |
string |
Yes | The hash of the transaction being approved. |
sharedSecret |
string |
Yes | Shared secret between the Wardex SDK and the signer process. |
timestamp |
number |
No | Unix timestamp in milliseconds. Defaults to Date.now(). |
string -- An 80-character hex string: 64 chars of HMAC + 16 chars of hex-encoded timestamp.
Verifies an approval token against a transaction hash using timing-safe comparison. Tokens expire after 5 minutes to prevent replay attacks.
import { verifyApprovalToken } from '@wardexai/signer';const isValid = verifyApprovalToken(
token,
'0xabc123...', // transaction hash
'shared-secret-between-sdk-and-signer'
);
if (!isValid) {
throw new Error('Invalid approval token');
}| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string |
Yes | The approval token to verify (80 hex characters). |
transactionHash |
string |
Yes | The hash of the transaction to verify against. |
sharedSecret |
string |
Yes | Shared secret between the Wardex SDK and the signer process. |
boolean -- true if the token is valid and not expired, false otherwise.
- Token must be exactly 80 hex characters.
- Timestamp embedded in the token must be within 5 minutes of the current time.
- HMAC comparison uses
crypto.timingSafeEqualto prevent timing attacks.
Verifies and consumes an approval token for one-time use. Prevents replay attacks by tracking used tokens within their validity window (5 minutes).
import { verifyAndConsumeApprovalToken } from '@wardexai/signer';const usedTokens = new Map<string, number>();
const isValid = verifyAndConsumeApprovalToken(
token,
'0xabc123...', // transaction hash
'shared-secret',
usedTokens
);
// Second attempt with same token returns false (replay prevention)
const isReplay = verifyAndConsumeApprovalToken(
token,
'0xabc123...',
'shared-secret',
usedTokens
); // false| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string |
Yes | The approval token to verify (80 hex characters). |
transactionHash |
string |
Yes | The hash of the transaction to verify against. |
sharedSecret |
string |
Yes | Shared secret between the Wardex SDK and the signer process. |
usedTokens |
Map<string, number> |
Yes | Replay cache mapping consumed tokens to their timestamps. Expired entries are automatically pruned. |
nowMs |
number |
No | Current time in milliseconds. Defaults to Date.now(). |
boolean -- true if the token is valid, not expired, and not previously consumed.
Creates a connection-authentication proof for the signer IPC handshake. The proof is HMAC(sharedSecret, "wardex-ipc-auth-v1:" + nonce), binding the client to possession of the shared secret.
import { generateConnectionAuthProof } from '@wardexai/signer';const proof = generateConnectionAuthProof(nonce, sharedSecret);
// Send proof to signer server to complete the auth handshake| Parameter | Type | Required | Description |
|---|---|---|---|
nonce |
string |
Yes | Random nonce received from the signer server's auth challenge. |
sharedSecret |
string |
Yes | Shared secret between the client and signer. |
string -- 64-character hex HMAC digest.
Verifies a connection-authentication proof using timing-safe comparison. Used internally by SignerServer to authenticate connecting clients.
import { verifyConnectionAuthProof } from '@wardexai/signer';const isValid = verifyConnectionAuthProof(nonce, sharedSecret, clientProof);| Parameter | Type | Required | Description |
|---|---|---|---|
nonce |
string |
Yes | The nonce that was sent in the auth challenge. |
sharedSecret |
string |
Yes | Shared secret between the client and signer. |
proof |
string |
Yes | The HMAC proof from the client (64 hex characters). |
boolean -- true if the proof is valid.
Computes the canonical Ethereum transaction hash (keccak256) from a serialized transaction. Used by SignerServer to verify that the claimed transaction hash matches the actual serialized payload, preventing hash substitution attacks.
import { computeSerializedTransactionHash } from '@wardexai/signer';const hash = computeSerializedTransactionHash('0xf86c...');
if (hash && hash.toLowerCase() === claimedHash.toLowerCase()) {
// Hash matches the payload
}| Parameter | Type | Required | Description |
|---|---|---|---|
serializedTx |
string |
Yes | Hex-encoded serialized transaction (must start with 0x). |
string | null -- The keccak256 hash of the transaction, or null if the input is not valid hex.
Conservative production defaults for session key boundaries. Use as a starting point and loosen explicitly as needed.
import { PRODUCTION_DEFAULTS } from '@wardexai/signer';| Field | Default | Description |
|---|---|---|
durationSeconds |
3600 |
1-hour session duration limits blast radius of compromised keys. |
maxValuePerTx |
'100000000000000000' |
0.1 ETH per-tx cap prevents large single losses. |
maxDailyVolume |
'1000000000000000000' |
1 ETH daily cap bounds total exposure. |
allowedContracts |
[] |
Empty — forces operator to explicitly define scope. |
forbidInfiniteApprovals |
true |
Infinite approvals forbidden by default. |
Creates a session config by merging user overrides onto PRODUCTION_DEFAULTS. Requires allowedContracts to be a non-empty array — sessions without an explicit contract allowlist are rejected.
import { createSessionWithDefaults } from '@wardexai/signer';const config = createSessionWithDefaults({
allowedContracts: ['0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45'],
maxValuePerTx: '500000000000000000', // Override to 0.5 ETH
});
// config.durationSeconds === 3600 (from PRODUCTION_DEFAULTS)
// config.forbidInfiniteApprovals === true (from PRODUCTION_DEFAULTS)| Parameter | Type | Required | Description |
|---|---|---|---|
overrides |
Partial<SessionKeyConfig> & { allowedContracts: string[] } |
Yes | Session config overrides. Must include a non-empty allowedContracts. |
SessionKeyConfig -- A complete config ready to pass to SessionManager.createSession().
Throws Error if allowedContracts is missing or empty.
Manages ERC-7715 scoped session keys for AI agent wallets. Session keys allow an agent to transact within strict, pre-defined boundaries without needing the full owner key for each operation.
import { SessionManager } from '@wardexai/signer';new SessionManager()No configuration parameters. The SessionManager maintains internal state for sessions, session states, and private keys.
Creates a new session key with the given boundaries. Generates a new keypair internally -- the private key never leaves the SessionManager.
createSession(config: SessionKeyConfig): SessionKey| Parameter | Type | Required | Description |
|---|---|---|---|
config |
SessionKeyConfig |
Yes | Session boundary configuration. |
const session = manager.createSession({
allowedContracts: ['0xUniswapRouter', '0xAaveLendingPool'],
// ...
});Type: string[] -- Allowed target contract addresses. Normalized to lowercase internally.
const session = manager.createSession({
maxValuePerTx: '100000000000000000', // 0.1 ETH
// ...
});Type: string -- Maximum value per single transaction in wei.
const session = manager.createSession({
maxDailyVolume: '1000000000000000000', // 1 ETH
// ...
});Type: string -- Maximum cumulative daily volume in wei. Resets at midnight.
const session = manager.createSession({
durationSeconds: 3600, // 1 hour
// ...
});Type: number -- Session duration in seconds from creation.
const session = manager.createSession({
forbidInfiniteApprovals: true,
// ...
});Type: boolean -- Whether to block ERC-20 approve calls with amounts exceeding 2^128 and setApprovalForAll calls.
SessionKey -- The session key metadata (private key stays internal).
const manager = new SessionManager();
const session = manager.createSession({
allowedContracts: ['0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'],
maxValuePerTx: '100000000000000000', // 0.1 ETH
maxDailyVolume: '1000000000000000000', // 1 ETH
durationSeconds: 3600, // 1 hour
forbidInfiniteApprovals: true,
});
console.log('Session ID:', session.id);
console.log('Session address:', session.address);
console.log('Expires at:', session.expiresAt);Validates whether a transaction is within the session key's boundaries. Checks revocation, expiration, target contract allowlist, per-transaction value limit, daily volume limit, and infinite approval blocking.
validateTransaction(
sessionId: string,
to: string,
value: string,
data?: string
): SessionValidationResult| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
Yes | The session key ID. |
to |
string |
Yes | Target address of the transaction. |
value |
string |
Yes | Transaction value in wei. |
data |
string |
No | Encoded calldata (checked for infinite approvals). |
SessionValidationResult
const result = manager.validateTransaction(
session.id,
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
'50000000000000000', // 0.05 ETH
);
if (!result.valid) {
console.error('Transaction rejected:', result.reason);
}Records a confirmed transaction against the session state. Call this after a transaction is successfully executed to update daily volume and transaction count tracking.
recordTransaction(sessionId: string, value: string, to: string): void| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
Yes | The session key ID. |
value |
string |
Yes | Transaction value in wei. |
to |
string |
Yes | Target address (tracked in contractsUsed). |
Immediately revokes a session key. Zeroes out the private key material in memory.
revokeSession(sessionId: string): boolean| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
Yes | The session key ID to revoke. |
boolean -- true if the session was found and revoked, false if not found.
Gets a session key by ID.
getSession(sessionId: string): SessionKey | undefined| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
Yes | The session key ID. |
SessionKey | undefined
Gets the current runtime state of a session, including daily volume spent, transaction count, and contracts used.
getSessionState(sessionId: string): SessionState | undefined| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
Yes | The session key ID. |
SessionState | undefined
Lists all active sessions (non-revoked, non-expired).
getActiveSessions(): SessionKey[]Rotates a session: revokes the old one and creates a new one with the same configuration but a fresh key and expiration.
rotateSession(sessionId: string): SessionKey | null| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
Yes | The session key ID to rotate. |
SessionKey | null -- The new session key, or null if the original was not found.
const newSession = manager.rotateSession(session.id);
if (newSession) {
console.log('Rotated to new session:', newSession.id);
}Gets sessions that are near expiration, within the given time window.
getExpiringSessionsSoon(withinSeconds: number): SessionKey[]| Parameter | Type | Required | Description |
|---|---|---|---|
withinSeconds |
number |
Yes | Time window in seconds. Returns sessions expiring within this window. |
// Find sessions expiring within the next 5 minutes
const expiring = manager.getExpiringSessionsSoon(300);
for (const session of expiring) {
manager.rotateSession(session.id);
}Removes all expired and revoked sessions from memory. Zeroes out any remaining private key material before deletion.
cleanup(): numbernumber -- The number of sessions removed.
Manages EIP-712 signed delegations backed by MetaMask's Delegation Framework. Mirrors the SessionManager API but produces on-chain-enforceable delegations with caveat enforcer contracts.
Key design: createDelegation() does not sign. Signing requires the owner's private key, which Wardex never holds. The owner calls getSigningPayload() to get the EIP-712 typed data, signs externally, then calls setSignature().
import { DelegationManager } from '@wardexai/signer';new DelegationManager(config: DelegationManagerConfig)| Parameter | Type | Required | Description |
|---|---|---|---|
config.chainId |
number |
Yes | Chain ID for EIP-712 domain separator. |
config.delegationManagerAddress |
string |
No | DelegationManager contract address. Defaults to canonical v1.3.0 deployment. |
config.enforcerAddresses |
Partial<EnforcerAddresses> |
No | Custom enforcer addresses (merged with canonical defaults). |
config.strictInfiniteApprovalBlocking |
boolean |
No | If true, adds AllowedMethodsEnforcer to block approve/setApprovalForAll at the contract level. |
Creates a new unsigned delegation with caveats mapped from a SessionKeyConfig. The delegation must be signed by the owner before it can be used.
createDelegation(
sessionConfig: SessionKeyConfig,
delegator: string
): WardexDelegation| Parameter | Type | Required | Description |
|---|---|---|---|
sessionConfig |
SessionKeyConfig |
Yes | Session boundaries to map to caveat enforcers. |
delegator |
string |
Yes | The owner address granting authority. |
WardexDelegation -- An unsigned delegation.
const dm = new DelegationManager({ chainId: 1 });
const delegation = dm.createDelegation(
{
allowedContracts: ['0xUniswapRouter'],
maxValuePerTx: '100000000000000000',
maxDailyVolume: '1000000000000000000',
durationSeconds: 3600,
forbidInfiniteApprovals: true,
},
'0xOwnerAddress'
);
console.log('Delegation ID:', delegation.id);
console.log('Delegate:', delegation.delegate);
console.log('Signed:', delegation.signature !== ''); // falseValidates whether a transaction is within the delegation's boundaries. Performs the same off-chain checks as SessionManager for defense-in-depth. On-chain enforcers provide the real backstop.
validateTransaction(
delegationId: string,
to: string,
value: string,
data?: string
): SessionValidationResult| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID. |
to |
string |
Yes | Target address. |
value |
string |
Yes | Transaction value in wei. |
data |
string |
No | Encoded calldata. |
SessionValidationResult
- Returns invalid if the delegation has not been signed (no
signature).
Records a confirmed transaction against the delegation state.
recordTransaction(delegationId: string, value: string): void| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID. |
value |
string |
Yes | Transaction value in wei. |
Immediately revokes a delegation.
revokeDelegation(delegationId: string): boolean| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID. |
boolean -- true if found and revoked, false if not found.
Rotates a delegation: revokes the old one and creates a new unsigned delegation with the same config and delegator.
rotateDelegation(delegationId: string): WardexDelegation | null| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID to rotate. |
WardexDelegation | null -- The new unsigned delegation, or null if the original was not found.
Gets a delegation by ID.
getDelegation(id: string): WardexDelegation | undefined| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | The delegation ID. |
WardexDelegation | undefined
Lists all active delegations (non-revoked, non-expired).
getActiveDelegations(): WardexDelegation[]Removes all expired and revoked delegations from memory.
cleanup(): numbernumber -- The number of delegations removed.
Returns the EIP-712 signing payload for a delegation. The owner must sign this payload externally to activate the delegation.
getSigningPayload(delegationId: string): {
domain: EIP712Domain;
types: Record<string, TypedDataField[]>;
value: Record<string, unknown>;
} | null| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID. |
An object with domain, types, and value suitable for EIP-712 signing, or null if not found.
const payload = dm.getSigningPayload(delegation.id);
if (payload) {
// Sign with ethers.js
const signature = await ownerWallet.signTypedData(
payload.domain,
payload.types,
payload.value
);
dm.setSignature(delegation.id, signature);
}Stores the EIP-712 signature for a delegation. Must be called after the owner signs the payload from getSigningPayload().
setSignature(delegationId: string, signature: string): void| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID. |
signature |
string |
Yes | The EIP-712 signature from the delegator. |
- Throws
Errorif the delegation is not found. - Throws
Errorif the delegation has been revoked.
Prepares the ABI-encoded calldata for redeeming a delegation via DeleGatorCore.redeemDelegations(). The returned calldata can be used in an ERC-4337 UserOp or sent directly to the DeleGatorCore contract.
prepareRedemption(
delegationId: string,
executions: Execution[]
): { target: string; value: bigint; calldata: string } | null| Parameter | Type | Required | Description |
|---|---|---|---|
delegationId |
string |
Yes | The delegation ID. |
executions |
Execution[] |
Yes | Array of operations to execute via delegated authority. |
{
target: string; // DelegationManager contract address
value: bigint; // Total native value across all executions
calldata: string; // ABI-encoded redeemDelegations calldata
} | nullReturns null if the delegation is not found or not signed.
const redemption = dm.prepareRedemption(delegation.id, [
{
target: '0xUniswapRouter',
value: 0n,
callData: '0x38ed1739...', // swapExactTokensForTokens calldata
},
]);
if (redemption) {
// Send as UserOp or direct transaction
await signer.sendTransaction({
to: redemption.target,
value: redemption.value,
data: redemption.calldata,
});
}Returns a copy of the enforcer addresses used by this DelegationManager instance.
getEnforcerAddresses(): EnforcerAddressesEnforcerAddresses
Maps a Wardex SessionKeyConfig to an array of caveat terms for a MetaMask Delegation Framework delegation. Each field in the config maps to a specific enforcer contract.
import { mapSessionConfigToCaveats } from '@wardexai/signer';import { mapSessionConfigToCaveats, getDefaultEnforcerAddresses } from '@wardexai/signer';
const caveats = mapSessionConfigToCaveats(
{
allowedContracts: ['0xUniswapRouter'],
maxValuePerTx: '100000000000000000',
maxDailyVolume: '1000000000000000000',
durationSeconds: 3600,
forbidInfiniteApprovals: true,
},
getDefaultEnforcerAddresses(),
{ strictInfiniteApprovalBlocking: true }
);| Parameter | Type | Required | Description |
|---|---|---|---|
config |
SessionKeyConfig |
Yes | Session boundaries to map. |
addresses |
EnforcerAddresses |
No | Enforcer contract addresses. Defaults to canonical v1.3.0 addresses. |
options.strictInfiniteApprovalBlocking |
boolean |
No | If true, adds AllowedMethodsEnforcer to block approve/setApprovalForAll at the contract level. Default: off-chain only. |
| SessionKeyConfig Field | Enforcer Contract | Encoding |
|---|---|---|
allowedContracts |
AllowedTargetsEnforcer |
abi.encode(address[]) |
maxValuePerTx |
ValueLteEnforcer |
abi.encode(uint256) |
maxDailyVolume |
NativeTokenPeriodTransferEnforcer |
abi.encode(uint256, uint256) (allowance, period=86400) |
durationSeconds |
TimestampEnforcer |
abi.encode(uint256, uint256) (after=0, before=now+duration) |
forbidInfiniteApprovals (strict) |
AllowedMethodsEnforcer |
abi.encode(bytes4[]) (safe selectors only) |
Returns the canonical enforcer contract addresses for MetaMask Delegation Framework v1.3.0. These addresses are the same on all 35+ supported EVM chains.
import { getDefaultEnforcerAddresses } from '@wardexai/signer';const addresses = getDefaultEnforcerAddresses();
console.log('AllowedTargets:', addresses.allowedTargets);
console.log('DelegationManager:', addresses.delegationManager);EnforcerAddresses
Low-level ABI encoding functions for individual enforcer terms. Used internally by mapSessionConfigToCaveats, but exported for advanced usage.
ABI-encodes contract addresses for the AllowedTargetsEnforcer.
encodeAllowedTargets(contracts: string[]): stringFormat: abi.encode(address[])
| Parameter | Type | Required | Description |
|---|---|---|---|
contracts |
string[] |
Yes | Array of allowed contract addresses. |
ABI-encodes the maximum native value for the ValueLteEnforcer.
encodeValueLte(maxWei: string): stringFormat: abi.encode(uint256)
| Parameter | Type | Required | Description |
|---|---|---|---|
maxWei |
string |
Yes | Maximum value in wei. |
ABI-encodes the expiration deadline for the TimestampEnforcer. Sets afterTimestamp=0 (no start constraint) and beforeTimestamp=now+durationSeconds.
encodeTimestamp(durationSeconds: number): stringFormat: abi.encode(uint256, uint256) -- (afterTimestamp, beforeTimestamp)
| Parameter | Type | Required | Description |
|---|---|---|---|
durationSeconds |
number |
Yes | Duration from now until expiry. |
ABI-encodes the volume limit for the NativeTokenPeriodTransferEnforcer.
encodeNativeTokenPeriod(maxWei: string, periodSeconds?: number): stringFormat: abi.encode(uint256, uint256) -- (allowance, period)
| Parameter | Type | Required | Description |
|---|---|---|---|
maxWei |
string |
Yes | Maximum native token transfer in the period (wei). |
periodSeconds |
number |
No | Period length in seconds. Default: 86400 (24 hours). |
ABI-encodes an allowlist of safe function selectors for the AllowedMethodsEnforcer, excluding approve and setApprovalForAll.
encodeBlockedApprovalMethods(): stringFormat: abi.encode(bytes4[])
Allowed selectors:
| Selector | Function |
|---|---|
0xa9059cbb |
transfer(address,uint256) |
0x23b872dd |
transferFrom(address,address,uint256) |
0x38ed1739 |
swapExactTokensForTokens |
0x8803dbee |
swapTokensForExactTokens |
0x5ae401dc |
multicall(uint256,bytes[]) |
Helpers for inspecting existing delegation caveat terms.
Decodes AllowedTargetsEnforcer terms back into an array of addresses.
decodeAllowedTargets(terms: string): string[]Decodes ValueLteEnforcer terms back into a max value (wei string).
decodeValueLte(terms: string): stringDecodes TimestampEnforcer terms back into timestamp values.
decodeTimestamp(terms: string): {
afterTimestamp: number;
beforeTimestamp: number;
}Decodes NativeTokenPeriodTransferEnforcer terms back into allowance and period.
decodeNativeTokenPeriod(terms: string): {
allowance: string;
periodSeconds: number;
}Getting Started
Concepts
Guides
- Guide: Protect an Ethers Agent
- Guide: Protect a Viem Agent
- Guide: Session Keys
- Guide: Delegation Framework
- Guide: MCP Server
- Guide: Claude Code Skill
- Guide: Custom Middleware
- Guide: Custom Policies
- Guide: Contract Deployment
API Reference
Security