# Dfns Typescript SDK The Dfns Typescript SDK provides a comprehensive interface for integrating with Dfns's MPC (Multi-Party Computation) wallet infrastructure. It enables developers to create and manage wallets, sign transactions, and interact with multiple blockchain networks while maintaining institutional-grade security through cryptographic request signing. The SDK supports both server-side (Node.js) and client-side (browser) applications, with specialized signers for WebAuthn passkeys, asymmetric keys, and React Native. At its core, the SDK implements a challenge-response authentication flow where all state-changing requests must be cryptographically signed by registered credentials. This ensures that only authorized users can perform sensitive operations like creating wallets or signing transactions. The SDK provides platform-specific integrations for over 20 blockchain ecosystems including Ethereum, Bitcoin, Solana, and many others through dedicated library packages. ## DfnsApiClient - Main API Client The `DfnsApiClient` is the primary interface for interacting with the Dfns API. It provides access to wallets, permissions, policies, webhooks, staking, and other Dfns services. All state-changing requests are automatically signed using the provided credential signer. ```typescript import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' // Initialize the credential signer with your service account credentials const signer = new AsymmetricKeySigner({ credId: 'cr-6qs5v-kg7pc-xxxxxxxxxxxxxxxx', // Credential ID from Dfns Dashboard privateKey: process.env.DFNS_PRIVATE_KEY!, // PEM-formatted private key }) // Create the API client const dfnsClient = new DfnsApiClient({ baseUrl: 'https://api.dfns.io', orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', // Your organization ID authToken: process.env.DFNS_AUTH_TOKEN!, // Service account or PAT token signer, }) // Create a new Ethereum wallet const wallet = await dfnsClient.wallets.createWallet({ body: { network: 'EthereumSepolia' } }) console.log('Created wallet:', wallet.id, wallet.address) // Output: Created wallet: wa-3p1nb-xxxxxx 0x1234...abcd // List all wallets const { items: wallets } = await dfnsClient.wallets.listWallets({}) console.log(`Total wallets: ${wallets.length}`) // Get wallet details with assets const walletDetails = await dfnsClient.wallets.getWallet({ walletId: wallet.id }) const { assets } = await dfnsClient.wallets.getWalletAssets({ walletId: wallet.id }) console.log('Wallet assets:', assets) ``` ## AsymmetricKeySigner - Server-Side Credential Signing The `AsymmetricKeySigner` implements the `CredentialSigner` interface for server-side applications. It signs user action challenges using an asymmetric key pair (typically Ed25519 or ECDSA). This signer is used with service accounts or Personal Access Tokens (PATs). ```typescript import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' import { DfnsApiClient } from '@dfns/sdk' // The private key should be securely stored (e.g., environment variable, secrets manager) const privateKeyPem = `-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEILpKMIKFoVZ4v1GWPn3y1R1VnMKbJ8HtR8k... -----END PRIVATE KEY-----` const signer = new AsymmetricKeySigner({ credId: 'cr-6qs5v-kg7pc-xxxxxxxxxxxxxxxx', privateKey: privateKeyPem, algorithm: 'Ed25519' // Optional: specify algorithm (defaults to key type detection) }) // Use with DfnsApiClient for automatic request signing const dfnsClient = new DfnsApiClient({ baseUrl: 'https://api.dfns.io', orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', authToken: process.env.DFNS_AUTH_TOKEN!, signer, }) // All state-changing operations are automatically signed const signature = await dfnsClient.wallets.generateSignature({ walletId: 'wa-3p1nb-xxxxxx', body: { kind: 'Hash', hash: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890' } }) console.log('Signature:', signature.signature?.r, signature.signature?.s) ``` ## WebAuthnSigner - Browser-Side Passkey Authentication The `WebAuthnSigner` enables passkey-based authentication in browser applications using WebAuthn (FIDO2). It implements both `CredentialSigner` and `CredentialStore` interfaces for signing challenges and creating new passkey credentials. ```typescript import { WebAuthnSigner } from '@dfns/sdk-browser' import { DfnsAuthenticator } from '@dfns/sdk' // Initialize WebAuthn signer with your domain's relying party information const webauthnSigner = new WebAuthnSigner({ relyingParty: { id: 'acme.com', // Use root domain for cross-subdomain passkey support name: 'Acme Corporation' // Display name shown to users }, timeout: 60000 // Optional: credential operation timeout in milliseconds }) // User login with passkeys const dfnsAuth = new DfnsAuthenticator({ orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', baseUrl: 'https://api.dfns.io', signer: webauthnSigner, }) // This triggers the browser's passkey prompt (TouchID, FaceID, etc.) const { token } = await dfnsAuth.login({ orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', username: 'user@example.com' }) console.log('User authenticated, token:', token) // User registration with new passkey const registrationResult = await dfnsAuth.register({ orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', username: 'newuser@example.com', registrationCode: 'reg-code-from-email' // Registration code sent to user }) console.log('User registered:', registrationResult.user.id) ``` ## DfnsDelegatedApiClient - Delegated Signing Flow The `DfnsDelegatedApiClient` enables server-initiated requests where the actual signing is delegated to the end user (typically in a browser). This is useful for web applications where the server orchestrates API calls but users sign with their own credentials. ```typescript import { DfnsDelegatedApiClient } from '@dfns/sdk' import { WebAuthnSigner } from '@dfns/sdk-browser' // SERVER SIDE: Initialize delegated client with user's auth token const delegatedClient = new DfnsDelegatedApiClient({ baseUrl: 'https://api.dfns.io', orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', authToken: userAuthToken, // Token from user's login session }) // SERVER: Initiate wallet creation (returns challenge for user to sign) const challenge = await delegatedClient.wallets.createWalletInit({ body: { network: 'EthereumSepolia' } }) // Send challenge to frontend... // CLIENT SIDE: User signs the challenge with their passkey const webauthnSigner = new WebAuthnSigner({ relyingParty: { id: 'acme.com', name: 'Acme' } }) const signedChallenge = await webauthnSigner.sign(challenge) // Send signedChallenge back to server... // SERVER: Complete the wallet creation with user's signed challenge const wallet = await delegatedClient.wallets.createWalletComplete( { body: { network: 'EthereumSepolia' } }, signedChallenge ) console.log('Wallet created:', wallet.id) ``` ## Wallets API - Create, Manage, and Sign The Wallets API provides comprehensive wallet management including creation, listing, signing, transactions, and transfers. Wallets can be created for various blockchain networks with different key schemes. ```typescript import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' const signer = new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }) const dfns = new DfnsApiClient({ baseUrl: process.env.DFNS_API_URL!, orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, signer, }) // Create wallets for different networks const ethWallet = await dfns.wallets.createWallet({ body: { network: 'EthereumSepolia' } }) const btcWallet = await dfns.wallets.createWallet({ body: { network: 'BitcoinTestnet3' } }) const solWallet = await dfns.wallets.createWallet({ body: { network: 'SolanaDevnet' } }) // Generate a signature (hash signing) const hashSignature = await dfns.wallets.generateSignature({ walletId: ethWallet.id, body: { kind: 'Hash', hash: '0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' } }) console.log('Hash signature:', hashSignature.signature) // Generate a signature (message signing for EVM) const messageSignature = await dfns.wallets.generateSignature({ walletId: ethWallet.id, body: { kind: 'Message', message: '0x48656c6c6f20576f726c64' // "Hello World" in hex } }) // Generate EIP-712 typed data signature const typedDataSignature = await dfns.wallets.generateSignature({ walletId: ethWallet.id, body: { kind: 'Eip712', domain: { name: 'MyDApp', version: '1', chainId: 11155111, verifyingContract: '0x1234...' }, types: { Message: [{ name: 'content', type: 'string' }] }, message: { content: 'Hello' } } }) // Broadcast a pre-signed transaction const txResult = await dfns.wallets.broadcastTransaction({ walletId: ethWallet.id, body: { kind: 'Evm', to: '0x1234567890123456789012345678901234567890', value: '1000000000000000', // 0.001 ETH in wei data: '0x' } }) console.log('Transaction ID:', txResult.id, 'Status:', txResult.status) // Transfer assets const transfer = await dfns.wallets.transferAsset({ walletId: ethWallet.id, body: { kind: 'Native', to: '0x1234567890123456789012345678901234567890', amount: '1000000000000000' } }) // Get wallet transaction history const { items: history } = await dfns.wallets.getWalletHistory({ walletId: ethWallet.id, query: { limit: '10' } }) ``` ## Ethers.js Integration (v6) The `@dfns/lib-ethersjs6` package provides a Dfns-backed signer compatible with ethers.js v6. It extends `AbstractSigner` and enables seamless integration with existing ethers.js code and dApps. ```typescript import { DfnsWallet } from '@dfns/lib-ethersjs6' import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' import { JsonRpcProvider, parseEther, Contract } from 'ethers' // Initialize Dfns client const signer = new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }) const dfnsClient = new DfnsApiClient({ orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, baseUrl: process.env.DFNS_API_URL!, signer, }) // Initialize Dfns wallet (fetches wallet metadata) const dfnsWallet = await DfnsWallet.init({ walletId: process.env.ETHEREUM_WALLET_ID!, dfnsClient, }) // Connect to Ethereum provider const provider = new JsonRpcProvider('https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY') const wallet = dfnsWallet.connect(provider) console.log('Wallet address:', await wallet.getAddress()) // Sign and send a transaction const tx = await wallet.sendTransaction({ to: '0x1234567890123456789012345678901234567890', value: parseEther('0.001'), }) console.log('Transaction hash:', tx.hash) await tx.wait() // Sign a message const signature = await wallet.signMessage('Hello, Dfns!') console.log('Message signature:', signature) // Interact with smart contracts const ERC20_ABI = ['function transfer(address to, uint256 amount) returns (bool)'] const tokenContract = new Contract('0xTokenAddress...', ERC20_ABI, wallet) const transferTx = await tokenContract.transfer( '0xRecipient...', parseEther('100') ) await transferTx.wait() ``` ## Viem Integration The `@dfns/lib-viem` package provides a Dfns-backed wallet compatible with viem. It can be used with viem's `toAccount` to create a local account for signing operations. ```typescript import { DfnsWallet } from '@dfns/lib-viem' import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' import { createWalletClient, http, parseEther } from 'viem' import { sepolia } from 'viem/chains' import { toAccount } from 'viem/accounts' // Initialize Dfns client const signer = new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }) const dfnsClient = new DfnsApiClient({ orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, baseUrl: process.env.DFNS_API_URL!, signer, }) // Initialize Dfns wallet const dfnsWallet = await DfnsWallet.init({ walletId: process.env.ETHEREUM_WALLET_ID!, dfnsClient, }) console.log('Wallet address:', dfnsWallet.address) // Create viem wallet client using Dfns wallet const walletClient = createWalletClient({ account: toAccount(dfnsWallet), chain: sepolia, transport: http('https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY'), }) // Send a transaction const hash = await walletClient.sendTransaction({ to: '0x1234567890123456789012345678901234567890', value: parseEther('0.001'), }) console.log('Transaction hash:', hash) // Sign a message const messageSignature = await dfnsWallet.signMessage({ message: 'Hello from Dfns!' }) console.log('Message signature:', messageSignature) // Sign typed data (EIP-712) const typedSignature = await dfnsWallet.signTypedData({ domain: { name: 'MyDApp', version: '1', chainId: 11155111, }, types: { Message: [{ name: 'content', type: 'string' }], }, primaryType: 'Message', message: { content: 'Hello' }, }) ``` ## Solana Integration The `@dfns/lib-solana` package provides a Dfns-backed wallet for Solana, supporting both legacy and versioned transactions with the `@solana/web3.js` library. ```typescript import { DfnsWallet } from '@dfns/lib-solana' import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' import { Connection, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, clusterApiUrl, } from '@solana/web3.js' // Initialize Dfns client const signer = new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }) const dfnsClient = new DfnsApiClient({ orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, baseUrl: process.env.DFNS_API_URL!, signer, }) // Initialize Dfns wallet for Solana const wallet = await DfnsWallet.init({ walletId: process.env.SOLANA_WALLET_ID!, dfnsClient, }) console.log('Solana address:', wallet.address) console.log('Public key:', wallet.publicKey.toBase58()) // Connect to Solana network const connection = new Connection(clusterApiUrl('devnet'), 'confirmed') const balance = await connection.getBalance(wallet.publicKey) console.log('Balance:', balance / 1e9, 'SOL') // Create and sign a transfer transaction const toAddress = new PublicKey('3U6stgsD1FmA7o3omUguritCU8iWmUM7Rs6KqAHHxHVZ') const amount = 100000000 // 0.1 SOL in lamports const latestBlockhash = await connection.getLatestBlockhash() const message = new TransactionMessage({ payerKey: wallet.publicKey, recentBlockhash: latestBlockhash.blockhash, instructions: [ SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: toAddress, lamports: BigInt(amount), }), ], }).compileToV0Message() const transaction = new VersionedTransaction(message) const signedTx = await wallet.signVersionedTransaction(transaction) // Broadcast the transaction const txid = await connection.sendRawTransaction(signedTx.serialize()) await connection.confirmTransaction({ signature: txid, ...latestBlockhash }) console.log('Transaction signature:', txid) ``` ## Bitcoin Integration (BitcoinJS) The `@dfns/lib-bitcoinjs` package enables Bitcoin transaction signing using Dfns wallets with the `bitcoinjs-lib` library. ```typescript import { DfnsWallet } from '@dfns/lib-bitcoinjs' import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' import { networks, payments, Psbt } from 'bitcoinjs-lib' // Initialize Dfns client const signer = new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }) const dfnsClient = new DfnsApiClient({ orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, baseUrl: process.env.DFNS_API_URL!, signer, }) // Initialize Dfns Bitcoin wallet const wallet = await DfnsWallet.init({ walletId: process.env.BITCOIN_WALLET_ID!, dfnsClient, }) const network = networks.testnet // Derive the wallet address from public key const { address } = payments.p2wpkh({ pubkey: wallet.publicKey, network }) console.log('Bitcoin address:', address) // Create a PSBT (Partially Signed Bitcoin Transaction) const psbt = new Psbt({ network }) // Add input (UTXO) psbt.addInput({ hash: '87872516c6e93f136fc6c493c7172596b11c695e27889de7532abffcac2a4b5e', index: 1, witnessUtxo: { script: Buffer.from('0014abc123...', 'hex'), // scriptPubKey value: 50000, // satoshis }, }) // Add outputs const fee = 150 const sendAmount = 1000 psbt.addOutput({ address: 'tb1q5s9xtdr07dk98ud0hr34ufdycz70exte2kehm2', // Recipient value: sendAmount, }) psbt.addOutput({ address: address!, // Change back to self value: 50000 - sendAmount - fee, }) // Sign the PSBT with Dfns wallet const signedPsbt = await wallet.SignPsbt(psbt) const finalizedPsbt = signedPsbt.finalizeAllInputs() const txHex = finalizedPsbt.extractTransaction().toHex() console.log('Signed transaction hex:', txHex) // Broadcast using Bitcoin node RPC or block explorer API ``` ## BaseAuthApi - Authentication Endpoints The `BaseAuthApi` provides static methods for authentication flows including login, registration, and recovery. These are lower-level APIs used by `DfnsAuthenticator` and can be used directly for custom authentication implementations. ```typescript import { BaseAuthApi } from '@dfns/sdk/baseAuthApi' import { WebAuthnSigner } from '@dfns/sdk-browser' const apiOptions = { baseUrl: 'https://api.dfns.io', orgId: 'or-2ng9jv-80cfc-xxxxxxxxxxxxxxxx', } // User Login Flow // Step 1: Create login challenge const loginChallenge = await BaseAuthApi.createUserLoginChallenge({ username: 'user@example.com', orgId: apiOptions.orgId, }, apiOptions) // Step 2: Sign challenge with WebAuthn const webauthn = new WebAuthnSigner({ relyingParty: { id: 'acme.com', name: 'Acme' } }) const assertion = await webauthn.sign(loginChallenge) // Step 3: Complete login const { token } = await BaseAuthApi.createUserLogin({ challengeIdentifier: loginChallenge.challengeIdentifier, firstFactor: assertion, }, apiOptions) console.log('Login successful, token:', token) // User Registration Flow // Step 1: Create registration challenge (requires registration code from invite) const regChallenge = await BaseAuthApi.createUserRegistrationChallenge({ orgId: apiOptions.orgId, username: 'newuser@example.com', registrationCode: 'reg-code-from-email', }, apiOptions) // Step 2: Create new passkey credential const attestation = await webauthn.create(regChallenge) // Step 3: Complete registration const registration = await BaseAuthApi.createUserRegistration({ firstFactorCredential: attestation, }, { ...apiOptions, authToken: regChallenge.temporaryAuthenticationToken, }) console.log('User registered:', registration.user.id) // Logout await BaseAuthApi.userLogout({ ...apiOptions, authToken: token, }) ``` ## Policies and Permissions API The Policies and Permissions APIs enable fine-grained access control and approval workflows for wallet operations. ```typescript import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' const dfns = new DfnsApiClient({ baseUrl: process.env.DFNS_API_URL!, orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, signer: new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }), }) // Create a policy requiring approval for large transfers const policy = await dfns.policies.createPolicy({ body: { name: 'Large Transfer Approval', activityKind: 'Wallets:TransferAsset', rule: { kind: 'TransferAmountLimit', configuration: { limit: '1000000000000000000', // 1 ETH in wei currency: 'ETH', }, }, action: { kind: 'RequestApproval', approvalGroups: [ { name: 'Finance Team', quorum: 2, // Requires 2 approvals approvers: { userIds: ['us-xxx', 'us-yyy', 'us-zzz'] } } ], }, filters: { walletTags: ['production'] // Apply to wallets tagged 'production' } } }) console.log('Policy created:', policy.id) // List policies const { items: policies } = await dfns.policies.listPolicies({}) console.log('Active policies:', policies.length) // Create a permission (assign to user or service account) const permission = await dfns.permissions.createPermission({ body: { name: 'Wallet Reader', operations: ['Wallets:Read', 'Wallets:ReadSignature'], } }) // Assign permission to users await dfns.permissions.createPermissionAssignment({ body: { permissionId: permission.id, identityId: 'us-user-id-xxx', } }) ``` ## Webhooks API The Webhooks API enables real-time notifications for wallet events like transactions, transfers, and policy approvals. ```typescript import { DfnsApiClient } from '@dfns/sdk' import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' const dfns = new DfnsApiClient({ baseUrl: process.env.DFNS_API_URL!, orgId: process.env.DFNS_ORG_ID!, authToken: process.env.DFNS_AUTH_TOKEN!, signer: new AsymmetricKeySigner({ credId: process.env.DFNS_CRED_ID!, privateKey: process.env.DFNS_PRIVATE_KEY!, }), }) // Create a webhook for wallet events const webhook = await dfns.webhooks.createWebhook({ body: { url: 'https://your-server.com/webhooks/dfns', events: [ 'wallet.transfer.confirmed', 'wallet.transaction.confirmed', 'wallet.signature.signed', 'policy.approval.pending', ], secret: 'your-webhook-secret-for-signature-verification', } }) console.log('Webhook created:', webhook.id) // List webhooks const { items: webhooks } = await dfns.webhooks.listWebhooks({}) // Delete webhook await dfns.webhooks.deleteWebhook({ webhookId: webhook.id }) ``` ## Summary The Dfns Typescript SDK is designed for building secure, institutional-grade wallet infrastructure. The primary use cases include: (1) **Server-side automation** with service accounts using `AsymmetricKeySigner` for backend systems that manage wallets programmatically, (2) **User-facing applications** with `WebAuthnSigner` for web apps where users authenticate with passkeys, and (3) **Delegated flows** with `DfnsDelegatedApiClient` for hybrid architectures where servers orchestrate operations but users retain signing authority. Integration patterns typically follow one of three approaches: Direct integration using `DfnsApiClient` for simple backend services, delegated integration for web applications that need user-controlled signing, or blockchain library integration (ethers.js, viem, Solana web3.js, etc.) for seamless dApp development. The SDK's modular architecture allows developers to import only the packages they need, with platform-specific integrations available for over 20 blockchain networks including Ethereum, Bitcoin, Solana, Cosmos, Polkadot, and many others.