remote-signer-client
v0.3.13
Published
JavaScript client for remote-signer service. Supports both browser and Node.js.
Maintainers
Readme
Remote Signer JavaScript Client
JavaScript/TypeScript client library for the remote-signer service. This library provides a convenient interface for interacting with the remote-signer API, including Ed25519 authentication, request signing, and polling for approval.
Installation
npm install remote-signer-clientQuick Start
import { RemoteSignerClient } from 'remote-signer-client';
const client = new RemoteSignerClient({
baseURL: 'http://localhost:8548',
apiKeyID: 'your-api-key-id',
privateKey: 'your-ed25519-private-key-hex',
});
// Check server health
const health = await client.health();
console.log('Server status:', health.status);
// Sign a personal message
const response = await client.sign({
chain_id: '1',
signer_address: '0x...',
sign_type: 'personal',
payload: {
message: 'Hello, World!',
},
}, true); // waitForApproval = true
console.log('Signature:', response.signature);Features
- Ed25519 Authentication: Secure request signing with replay protection
- Multiple Sign Types: Support for personal messages, transactions, EIP-712, hash signing, etc.
- Automatic Polling: Wait for manual approval with configurable polling
- TypeScript Support: Full type definitions included
- Error Handling: Comprehensive error types and handling
API Reference
Constructor
new RemoteSignerClient(config: ClientConfig)Config Options:
baseURL(string, required): Base URL of the remote-signer serviceapiKeyID(string, required): API key identifierprivateKey(string | Uint8Array, required): Ed25519 private key (hex string or bytes)pollInterval(number, optional): Polling interval in milliseconds (default: 2000)pollTimeout(number, optional): Polling timeout in milliseconds (default: 300000)
Methods
health(): Promise<HealthResponse>
Check server health status.
const health = await client.health();
// { status: 'healthy', version: '1.0.0' }sign(request: SignRequest, waitForApproval?: boolean): Promise<SignResponse>
Submit a signing request.
const response = await client.sign({
chain_id: '1',
signer_address: '0x...',
sign_type: 'personal',
payload: {
message: 'Hello, World!',
},
}, true); // waitForApprovalSign Types:
personal: Personal message (adds Ethereum prefix)eip191: EIP-191 formatted messagetyped_data: EIP-712 typed datatransaction: Ethereum transactionhash: Pre-hashed 32-byte valueraw_message: Raw bytes
getRequest(requestID: string): Promise<RequestStatusResponse>
Get the status of a signing request.
const request = await client.getRequest('request-id');listRequests(filter?: ListRequestsFilter): Promise<ListRequestsResponse>
List signing requests with optional filters.
const requests = await client.listRequests({
status: 'completed',
signer_address: '0x...',
limit: 10,
});approveRequest(requestID: string, approveRequest: ApproveRequest): Promise<ApproveResponse>
Approve or reject a pending request (admin only).
const response = await client.approveRequest('request-id', {
approved: true,
});evm.simulate(request: SimulateRequest): Promise<SimulateResponse>
Simulate a single transaction.
const result = await client.evm.simulate({
chainId: '1',
from: '0x...',
to: '0x...',
value: '0x0',
data: '0x...',
});evm.simulateBatch(request: SimulateBatchRequest): Promise<SimulateBatchResponse>
Simulate multiple transactions in sequence.
const result = await client.evm.simulateBatch({
chainId: '1',
from: '0x...',
transactions: [
{ to: '0x...', value: '0x0', data: '0x...' },
{ to: '0x...', value: '0x0', data: '0x...' },
],
});evm.simulate.status(): Promise<SimulateStatusResponse>
Check simulation engine health/status.
evm.sign.executeBatch(request: BatchSignRequest): Promise<BatchSignResponse>
Sign multiple transactions atomically (simulate + sign).
const result = await client.evm.sign.executeBatch({
requests: [
{ chain_id: '1', signer_address: '0x...', sign_type: 'transaction', payload: { ... } },
{ chain_id: '1', signer_address: '0x...', sign_type: 'transaction', payload: { ... } },
],
});Signer Access Control
// Grant access to another API key
await client.evm.signers.grantAccess('0xAddr', { api_key_id: 'other-key' });
// Revoke access
await client.evm.signers.revokeAccess('0xAddr', 'other-key');
// List access
const access = await client.evm.signers.listAccess('0xAddr');
// Transfer ownership
await client.evm.signers.transferOwnership('0xAddr', { new_owner_id: 'new-admin' });
// Delete signer
await client.evm.signers.deleteSigner('0xAddr');Rule Approval
Only the signer's owner API key can approve or reject pending requests:
await client.approveRequest('request-id', { approved: true });
await client.approveRequest('request-id', { approved: false });Error Handling
The client throws specific error types:
APIError: API request errors (4xx, 5xx)SignError: Signing request errors (rejected, failed)TimeoutError: Polling timeout errorsRemoteSignerError: General client errors
import { APIError, SignError, TimeoutError } from 'remote-signer-client';
try {
await client.sign(request, true);
} catch (error) {
if (error instanceof SignError) {
console.error('Signing failed:', error.message);
console.error('Request ID:', error.requestID);
console.error('Status:', error.status);
} else if (error instanceof TimeoutError) {
console.error('Request timed out');
} else if (error instanceof APIError) {
console.error('API error:', error.statusCode, error.message);
}
}Examples
See examples/basic-usage.ts for more examples.
Development
Building
npm run buildTesting
Unit Tests
npm run test:unitE2E Tests
E2E tests require a running remote-signer server. See tests/README.md for details.
Quick start:
# Option 1: Use external server
export E2E_EXTERNAL_SERVER=true
export E2E_BASE_URL=http://localhost:8548
export E2E_API_KEY_ID=your-api-key-id
export E2E_PRIVATE_KEY=your-private-key-hex
npm run test:e2e
# Option 2: Start test server automatically
./scripts/start-test-server.sh &
sleep 5
npm run test:e2eLinting
npm run lintPublishing to npm
The package is unscoped (remote-signer-client), same style as eip155-chains: no org needed, always public.
Auth (one-time per machine): set a token in
~/.npmrc:echo "//registry.npmjs.org/:_authToken=YOUR_NPM_TOKEN" >> ~/.npmrc chmod 600 ~/.npmrcCreate a token at npmjs.com → Account → Access Tokens (Automation or Publish).
Build and publish from this directory:
cd pkg/js-client npm run build npm publishUnscoped packages are public by default; no
--access publicneeded.Subsequent releases: bump
versioninpackage.json(ornpm version patch), thennpm publishagain.
License
MIT
