@solana/keychain-dfns 0.0.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -0
- package/dist/__tests__/dfns-signer.integration.test.d.ts +2 -0
- package/dist/__tests__/dfns-signer.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dfns-signer.integration.test.js +17 -0
- package/dist/__tests__/dfns-signer.integration.test.js.map +1 -0
- package/dist/__tests__/dfns-signer.test.d.ts +2 -0
- package/dist/__tests__/dfns-signer.test.d.ts.map +1 -0
- package/dist/__tests__/dfns-signer.test.js +157 -0
- package/dist/__tests__/dfns-signer.test.js.map +1 -0
- package/dist/__tests__/setup.d.ts +45 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +64 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/auth.d.ts +7 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +117 -0
- package/dist/auth.js.map +1 -0
- package/dist/dfns-signer.d.ts +65 -0
- package/dist/dfns-signer.d.ts.map +1 -0
- package/dist/dfns-signer.js +331 -0
- package/dist/dfns-signer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -8
- package/src/__tests__/dfns-signer.integration.test.ts +17 -0
- package/src/__tests__/dfns-signer.test.ts +217 -0
- package/src/__tests__/setup.ts +76 -0
- package/src/auth.ts +136 -0
- package/src/dfns-signer.ts +421 -0
- package/src/index.ts +2 -0
- package/src/types.ts +113 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { Address, assertIsAddress } from '@solana/addresses';
|
|
2
|
+
import { getBase16Decoder, getBase16Encoder, getBase58Decoder } from '@solana/codecs-strings';
|
|
3
|
+
import {
|
|
4
|
+
assertSignatureValid,
|
|
5
|
+
createSignatureDictionary,
|
|
6
|
+
SignerErrorCode,
|
|
7
|
+
SolanaSigner,
|
|
8
|
+
throwSignerError,
|
|
9
|
+
} from '@solana/keychain-core';
|
|
10
|
+
import { SignatureBytes } from '@solana/keys';
|
|
11
|
+
import { SignableMessage, SignatureDictionary } from '@solana/signers';
|
|
12
|
+
import {
|
|
13
|
+
getTransactionEncoder,
|
|
14
|
+
Transaction,
|
|
15
|
+
TransactionWithinSizeLimit,
|
|
16
|
+
TransactionWithLifetime,
|
|
17
|
+
} from '@solana/transactions';
|
|
18
|
+
|
|
19
|
+
import { signUserAction } from './auth.js';
|
|
20
|
+
import type {
|
|
21
|
+
DfnsSignerConfig,
|
|
22
|
+
GenerateSignatureRequest,
|
|
23
|
+
GenerateSignatureResponse,
|
|
24
|
+
GetWalletResponse,
|
|
25
|
+
} from './types.js';
|
|
26
|
+
|
|
27
|
+
export async function createDfnsSigner<TAddress extends string = string>(
|
|
28
|
+
config: DfnsSignerConfig,
|
|
29
|
+
): Promise<SolanaSigner<TAddress>> {
|
|
30
|
+
return await DfnsSigner.create(config);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const DEFAULT_API_BASE_URL = 'https://api.dfns.io';
|
|
34
|
+
|
|
35
|
+
let base16Encoder: ReturnType<typeof getBase16Encoder> | undefined;
|
|
36
|
+
let base16Decoder: ReturnType<typeof getBase16Decoder> | undefined;
|
|
37
|
+
let base58Decoder: ReturnType<typeof getBase58Decoder> | undefined;
|
|
38
|
+
|
|
39
|
+
function hexToBytes(hex: string): Uint8Array {
|
|
40
|
+
base16Encoder ||= getBase16Encoder();
|
|
41
|
+
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
42
|
+
return new Uint8Array(base16Encoder.encode(clean));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function bytesToHex(bytes: Uint8Array): string {
|
|
46
|
+
base16Decoder ||= getBase16Decoder();
|
|
47
|
+
return base16Decoder.decode(bytes);
|
|
48
|
+
}
|
|
49
|
+
function bytesToBase58(bytes: Uint8Array): string {
|
|
50
|
+
base58Decoder ||= getBase58Decoder();
|
|
51
|
+
return base58Decoder.decode(bytes);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Dfns-based signer for Solana transactions.
|
|
56
|
+
*
|
|
57
|
+
* Uses Dfns Keys API to sign Solana transactions and messages.
|
|
58
|
+
* Requires a Dfns account with an active Ed25519 Solana wallet.
|
|
59
|
+
*
|
|
60
|
+
* Use the static `create()` factory to construct an instance — it validates
|
|
61
|
+
* the wallet status, key scheme, and curve via the Dfns API.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const signer = await DfnsSigner.create({
|
|
66
|
+
* authToken: 'your-service-account-token',
|
|
67
|
+
* credId: 'your-credential-id',
|
|
68
|
+
* privateKeyPem: '-----BEGIN PRIVATE KEY-----\n...',
|
|
69
|
+
* walletId: 'your-wallet-id',
|
|
70
|
+
* });
|
|
71
|
+
* const signed = await signTransactionMessageWithSigners(transactionMessage, [signer]);
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @deprecated Prefer `createDfnsSigner()`. Class export will be removed in a future version.
|
|
75
|
+
*/
|
|
76
|
+
export class DfnsSigner<TAddress extends string = string> implements SolanaSigner<TAddress> {
|
|
77
|
+
readonly address: Address<TAddress>;
|
|
78
|
+
private readonly authToken: string;
|
|
79
|
+
private readonly credId: string;
|
|
80
|
+
private readonly privateKeyPem: string;
|
|
81
|
+
private readonly walletId: string;
|
|
82
|
+
private readonly apiBaseUrl: string;
|
|
83
|
+
private readonly keyId: string;
|
|
84
|
+
|
|
85
|
+
private readonly requestDelayMs: number;
|
|
86
|
+
|
|
87
|
+
private constructor(config: {
|
|
88
|
+
address: Address<TAddress>;
|
|
89
|
+
apiBaseUrl: string;
|
|
90
|
+
authToken: string;
|
|
91
|
+
credId: string;
|
|
92
|
+
keyId: string;
|
|
93
|
+
privateKeyPem: string;
|
|
94
|
+
requestDelayMs: number;
|
|
95
|
+
walletId: string;
|
|
96
|
+
}) {
|
|
97
|
+
this.address = config.address;
|
|
98
|
+
this.authToken = config.authToken;
|
|
99
|
+
this.credId = config.credId;
|
|
100
|
+
this.privateKeyPem = config.privateKeyPem;
|
|
101
|
+
this.walletId = config.walletId;
|
|
102
|
+
this.apiBaseUrl = config.apiBaseUrl;
|
|
103
|
+
this.keyId = config.keyId;
|
|
104
|
+
this.requestDelayMs = config.requestDelayMs;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Create and initialize a DfnsSigner.
|
|
109
|
+
*
|
|
110
|
+
* Validates config fields, fetches the wallet from Dfns, and checks that
|
|
111
|
+
* the wallet is active with an EdDSA/ed25519 signing key.
|
|
112
|
+
* @deprecated Use `createDfnsSigner()` instead.
|
|
113
|
+
*/
|
|
114
|
+
static async create<TAddress extends string = string>(config: DfnsSignerConfig): Promise<DfnsSigner<TAddress>> {
|
|
115
|
+
if (!config.authToken) {
|
|
116
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
117
|
+
message: 'Missing required authToken field',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!config.credId) {
|
|
122
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
123
|
+
message: 'Missing required credId field',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!config.privateKeyPem) {
|
|
128
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
129
|
+
message: 'Missing required privateKeyPem field',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!config.walletId) {
|
|
134
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
135
|
+
message: 'Missing required walletId field',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const apiBaseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
|
|
140
|
+
const requestDelayMs = config.requestDelayMs ?? 0;
|
|
141
|
+
|
|
142
|
+
if (requestDelayMs < 0) {
|
|
143
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
144
|
+
message: 'requestDelayMs must not be negative',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (requestDelayMs > 3000) {
|
|
148
|
+
console.warn(
|
|
149
|
+
'requestDelayMs is greater than 3000ms, this may result in blockhash expiration errors for signing messages/transactions',
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const wallet = await fetchWallet(apiBaseUrl, config.authToken, config.walletId);
|
|
154
|
+
|
|
155
|
+
if (wallet.status !== 'Active') {
|
|
156
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
157
|
+
message: `Wallet is not active: ${wallet.status}`,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (wallet.signingKey.scheme !== 'EdDSA') {
|
|
162
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
163
|
+
message: `Unsupported key scheme: ${wallet.signingKey.scheme} (expected EdDSA)`,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (wallet.signingKey.curve !== 'ed25519') {
|
|
168
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
169
|
+
message: `Unsupported key curve: ${wallet.signingKey.curve} (expected ed25519)`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const pubkeyBytes = hexToBytes(wallet.signingKey.publicKey);
|
|
174
|
+
const bs58Address = bytesToBase58(pubkeyBytes);
|
|
175
|
+
|
|
176
|
+
let address: Address<TAddress>;
|
|
177
|
+
try {
|
|
178
|
+
assertIsAddress(bs58Address);
|
|
179
|
+
address = bs58Address as Address<TAddress>;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throwSignerError(SignerErrorCode.INVALID_PUBLIC_KEY, {
|
|
182
|
+
cause: error,
|
|
183
|
+
message: 'Invalid public key from Dfns wallet',
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return new DfnsSigner<TAddress>({
|
|
188
|
+
address,
|
|
189
|
+
apiBaseUrl,
|
|
190
|
+
authToken: config.authToken,
|
|
191
|
+
credId: config.credId,
|
|
192
|
+
keyId: wallet.signingKey.id,
|
|
193
|
+
privateKeyPem: config.privateKeyPem,
|
|
194
|
+
requestDelayMs,
|
|
195
|
+
walletId: config.walletId,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async delay(index: number): Promise<void> {
|
|
200
|
+
if (this.requestDelayMs > 0 && index > 0) {
|
|
201
|
+
await new Promise(resolve => setTimeout(resolve, index * this.requestDelayMs));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Sign multiple messages using Dfns
|
|
207
|
+
*/
|
|
208
|
+
async signMessages(messages: readonly SignableMessage[]): Promise<readonly SignatureDictionary[]> {
|
|
209
|
+
return await Promise.all(
|
|
210
|
+
messages.map(async (message, index) => {
|
|
211
|
+
await this.delay(index);
|
|
212
|
+
const messageBytes =
|
|
213
|
+
message.content instanceof Uint8Array
|
|
214
|
+
? message.content
|
|
215
|
+
: new Uint8Array(Array.from(message.content));
|
|
216
|
+
const signatureBytes = await this.sendSignatureRequest({
|
|
217
|
+
kind: 'Message',
|
|
218
|
+
message: `0x${bytesToHex(messageBytes)}`,
|
|
219
|
+
});
|
|
220
|
+
await assertSignatureValid({
|
|
221
|
+
data: messageBytes,
|
|
222
|
+
signature: signatureBytes,
|
|
223
|
+
signerAddress: this.address,
|
|
224
|
+
});
|
|
225
|
+
return createSignatureDictionary({
|
|
226
|
+
signature: signatureBytes,
|
|
227
|
+
signerAddress: this.address,
|
|
228
|
+
});
|
|
229
|
+
}),
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Sign multiple transactions using Dfns
|
|
235
|
+
*/
|
|
236
|
+
async signTransactions(
|
|
237
|
+
transactions: readonly (Transaction & TransactionWithinSizeLimit & TransactionWithLifetime)[],
|
|
238
|
+
): Promise<readonly SignatureDictionary[]> {
|
|
239
|
+
const txEncoder = getTransactionEncoder();
|
|
240
|
+
return await Promise.all(
|
|
241
|
+
transactions.map(async (transaction, index) => {
|
|
242
|
+
await this.delay(index);
|
|
243
|
+
const txBytes = txEncoder.encode(transaction);
|
|
244
|
+
const signatureBytes = await this.sendSignatureRequest({
|
|
245
|
+
blockchainKind: 'Solana',
|
|
246
|
+
kind: 'Transaction',
|
|
247
|
+
transaction: `0x${bytesToHex(new Uint8Array(txBytes))}`,
|
|
248
|
+
});
|
|
249
|
+
await assertSignatureValid({
|
|
250
|
+
data: transaction.messageBytes,
|
|
251
|
+
signature: signatureBytes,
|
|
252
|
+
signerAddress: this.address,
|
|
253
|
+
});
|
|
254
|
+
return createSignatureDictionary({
|
|
255
|
+
signature: signatureBytes,
|
|
256
|
+
signerAddress: this.address,
|
|
257
|
+
});
|
|
258
|
+
}),
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Check if Dfns API is available
|
|
264
|
+
*/
|
|
265
|
+
async isAvailable(): Promise<boolean> {
|
|
266
|
+
try {
|
|
267
|
+
await fetchWallet(this.apiBaseUrl, this.authToken, this.walletId);
|
|
268
|
+
return true;
|
|
269
|
+
} catch {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Send a signature request to the Dfns Keys API
|
|
276
|
+
*/
|
|
277
|
+
private async sendSignatureRequest(request: GenerateSignatureRequest): Promise<SignatureBytes> {
|
|
278
|
+
const httpPath = `/keys/${this.keyId}/signatures`;
|
|
279
|
+
const requestBody = JSON.stringify(request);
|
|
280
|
+
|
|
281
|
+
const userAction = await signUserAction(
|
|
282
|
+
this.apiBaseUrl,
|
|
283
|
+
this.authToken,
|
|
284
|
+
this.credId,
|
|
285
|
+
this.privateKeyPem,
|
|
286
|
+
'POST',
|
|
287
|
+
httpPath,
|
|
288
|
+
requestBody,
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const url = `${this.apiBaseUrl}${httpPath}`;
|
|
292
|
+
let response: Response;
|
|
293
|
+
try {
|
|
294
|
+
response = await fetch(url, {
|
|
295
|
+
body: requestBody,
|
|
296
|
+
headers: {
|
|
297
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
298
|
+
'Content-Type': 'application/json',
|
|
299
|
+
'x-dfns-useraction': userAction,
|
|
300
|
+
},
|
|
301
|
+
method: 'POST',
|
|
302
|
+
});
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throwSignerError(SignerErrorCode.HTTP_ERROR, {
|
|
305
|
+
cause: error,
|
|
306
|
+
message: 'Dfns network request failed',
|
|
307
|
+
url,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
const errorText = await response.text().catch(() => 'Failed to read error response');
|
|
313
|
+
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
314
|
+
message: `Dfns signing API error: ${response.status}`,
|
|
315
|
+
response: errorText,
|
|
316
|
+
status: response.status,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
let sigResponse: GenerateSignatureResponse;
|
|
321
|
+
try {
|
|
322
|
+
sigResponse = (await response.json()) as GenerateSignatureResponse;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
throwSignerError(SignerErrorCode.PARSING_ERROR, {
|
|
325
|
+
cause: error,
|
|
326
|
+
message: 'Failed to parse Dfns signature response',
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (sigResponse.status === 'Failed') {
|
|
331
|
+
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
332
|
+
message: 'Dfns signing failed',
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (sigResponse.status !== 'Signed') {
|
|
337
|
+
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
338
|
+
message: `Unexpected signature status: ${sigResponse.status} (may require policy approval)`,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (!sigResponse.signature) {
|
|
343
|
+
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
344
|
+
message: 'Signature components missing from response',
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return combineSignature(sigResponse.signature.r, sigResponse.signature.s);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Fetch wallet details from Dfns
|
|
354
|
+
*/
|
|
355
|
+
async function fetchWallet(apiBaseUrl: string, authToken: string, walletId: string): Promise<GetWalletResponse> {
|
|
356
|
+
const url = `${apiBaseUrl}/wallets/${walletId}`;
|
|
357
|
+
let response: Response;
|
|
358
|
+
try {
|
|
359
|
+
response = await fetch(url, {
|
|
360
|
+
headers: {
|
|
361
|
+
Authorization: `Bearer ${authToken}`,
|
|
362
|
+
},
|
|
363
|
+
method: 'GET',
|
|
364
|
+
});
|
|
365
|
+
} catch (error) {
|
|
366
|
+
throwSignerError(SignerErrorCode.HTTP_ERROR, {
|
|
367
|
+
cause: error,
|
|
368
|
+
message: 'Dfns network request failed',
|
|
369
|
+
url,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!response.ok) {
|
|
374
|
+
const errorText = await response.text().catch(() => 'Failed to read error response');
|
|
375
|
+
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
376
|
+
message: `Dfns API error: ${response.status}`,
|
|
377
|
+
response: errorText,
|
|
378
|
+
status: response.status,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
try {
|
|
383
|
+
return (await response.json()) as GetWalletResponse;
|
|
384
|
+
} catch (error) {
|
|
385
|
+
throwSignerError(SignerErrorCode.PARSING_ERROR, {
|
|
386
|
+
cause: error,
|
|
387
|
+
message: 'Failed to parse Dfns wallet response',
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Pad signature component to exactly 32 bytes.
|
|
394
|
+
* Components from Dfns may be shorter than 32 bytes and need left-padding with zeros.
|
|
395
|
+
*/
|
|
396
|
+
function padSignatureComponent(hex: string): Uint8Array {
|
|
397
|
+
const bytes = hexToBytes(hex);
|
|
398
|
+
|
|
399
|
+
if (bytes.length > 32) {
|
|
400
|
+
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
401
|
+
message: `Invalid signature component length: ${bytes.length} (max 32)`,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const padded = new Uint8Array(32);
|
|
406
|
+
padded.set(bytes, 32 - bytes.length);
|
|
407
|
+
return padded;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Combine r and s hex-encoded components into a 64-byte Ed25519 signature.
|
|
412
|
+
* Each component is individually validated and left-padded to 32 bytes.
|
|
413
|
+
*/
|
|
414
|
+
function combineSignature(r: string, s: string): SignatureBytes {
|
|
415
|
+
const rBytes = padSignatureComponent(r);
|
|
416
|
+
const sBytes = padSignatureComponent(s);
|
|
417
|
+
const combined = new Uint8Array(64);
|
|
418
|
+
combined.set(rBytes, 0);
|
|
419
|
+
combined.set(sBytes, 32);
|
|
420
|
+
return combined as SignatureBytes;
|
|
421
|
+
}
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for creating a DfnsSigner
|
|
3
|
+
*/
|
|
4
|
+
export interface DfnsSignerConfig {
|
|
5
|
+
/** API base URL (default: "https://api.dfns.io") */
|
|
6
|
+
apiBaseUrl?: string;
|
|
7
|
+
|
|
8
|
+
/** Service account token or personal access token */
|
|
9
|
+
authToken: string;
|
|
10
|
+
|
|
11
|
+
/** Credential ID for user action signing */
|
|
12
|
+
credId: string;
|
|
13
|
+
|
|
14
|
+
/** Private key in PEM format for signing user action challenges (Ed25519, P256, or RSA) */
|
|
15
|
+
privateKeyPem: string;
|
|
16
|
+
|
|
17
|
+
/** Optional delay in ms between concurrent signing requests to avoid rate limits (default: 0) */
|
|
18
|
+
requestDelayMs?: number;
|
|
19
|
+
|
|
20
|
+
/** Dfns wallet ID */
|
|
21
|
+
walletId: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Dfns wallet response
|
|
26
|
+
*/
|
|
27
|
+
export interface GetWalletResponse {
|
|
28
|
+
id: string;
|
|
29
|
+
signingKey: {
|
|
30
|
+
curve: string;
|
|
31
|
+
id: string;
|
|
32
|
+
publicKey: string;
|
|
33
|
+
scheme: string;
|
|
34
|
+
};
|
|
35
|
+
status: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Message signature request body for Dfns Keys API
|
|
40
|
+
*/
|
|
41
|
+
export interface GenerateMessageSignatureRequest {
|
|
42
|
+
kind: 'Message';
|
|
43
|
+
message: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Transaction signature request body for Dfns Keys API
|
|
48
|
+
*/
|
|
49
|
+
export interface GenerateTransactionSignatureRequest {
|
|
50
|
+
blockchainKind: string;
|
|
51
|
+
kind: 'Transaction';
|
|
52
|
+
transaction: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type GenerateSignatureRequest = GenerateMessageSignatureRequest | GenerateTransactionSignatureRequest;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Signature response from Dfns Keys API
|
|
59
|
+
*/
|
|
60
|
+
export interface GenerateSignatureResponse {
|
|
61
|
+
id: string;
|
|
62
|
+
signature?: SignatureComponents;
|
|
63
|
+
signedData?: string;
|
|
64
|
+
status: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface SignatureComponents {
|
|
68
|
+
r: string;
|
|
69
|
+
s: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* User action challenge init request
|
|
74
|
+
*/
|
|
75
|
+
export interface UserActionInitRequest {
|
|
76
|
+
userActionHttpMethod: string;
|
|
77
|
+
userActionHttpPath: string;
|
|
78
|
+
userActionPayload: string;
|
|
79
|
+
userActionServerKind: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* User action challenge init response
|
|
84
|
+
*/
|
|
85
|
+
export interface UserActionInitResponse {
|
|
86
|
+
allowCredentials: {
|
|
87
|
+
key: Array<{ id: string }>;
|
|
88
|
+
};
|
|
89
|
+
challenge: string;
|
|
90
|
+
challengeIdentifier: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* User action sign request
|
|
95
|
+
*/
|
|
96
|
+
export interface UserActionSignRequest {
|
|
97
|
+
challengeIdentifier: string;
|
|
98
|
+
firstFactor: {
|
|
99
|
+
credentialAssertion: {
|
|
100
|
+
clientData: string;
|
|
101
|
+
credId: string;
|
|
102
|
+
signature: string;
|
|
103
|
+
};
|
|
104
|
+
kind: string;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* User action sign response
|
|
110
|
+
*/
|
|
111
|
+
export interface UserActionResponse {
|
|
112
|
+
userAction: string;
|
|
113
|
+
}
|