{"_id":"@solana/keychain-fordefi","_rev":"3-329c967b7dbec68ac750c19884159e73","name":"@solana/keychain-fordefi","dist-tags":{"latest":"2.0.0","beta":"2.0.0-beta.1"},"versions":{"0.0.0":{"name":"@solana/keychain-fordefi","version":"0.0.0","author":"","license":"ISC","_id":"@solana/keychain-fordefi@0.0.0","maintainers":[{"name":"solana-devs","email":"npm@solana.org"}],"dist":{"shasum":"08617aaa8bc7a5aaa39a41c3ad9d54f73b636d0d","tarball":"https://registry.npmjs.org/@solana/keychain-fordefi/-/keychain-fordefi-0.0.0.tgz","fileCount":1,"integrity":"sha512-FFy7XYMx3IeKah29zjmM63mLNyb/QifaU51CZqb2ddprQ1NKn0HNRwHD11eMd+IrvuuFCdaUdo7fbVNcZ3+2zA==","signatures":[{"sig":"MEUCICKCimwZIHBBm//8UULCLmuiwh+G8kIQcG6cIGzfDWSbAiEAmPmw0LZ9DhfdbEpjARmnecdvXfSV9YzAdjbYvIuZW6Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":242},"main":"index.js","type":"commonjs","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"solana-devs","email":"npm@solana.org"},"_npmVersion":"11.12.1","description":"","directories":{},"_nodeVersion":"24.10.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/keychain-fordefi_0.0.0_1785254882454_0.36415122207711836","host":"s3://npm-registry-packages-npm-production"}},"2.0.0-beta.1":{"name":"@solana/keychain-fordefi","version":"2.0.0-beta.1","keywords":["solana","signing","wallet","fordefi","mpc","custody"],"author":{"name":"Solana Foundation"},"license":"MIT","_id":"@solana/keychain-fordefi@2.0.0-beta.1","maintainers":[{"name":"solana-devs","email":"npm@solana.org"}],"homepage":"https://github.com/solana-foundation/solana-keychain#readme","bugs":{"url":"https://github.com/solana-foundation/solana-keychain/issues"},"dist":{"shasum":"f4ea620209f3a23f322e542ccef77e63b4e87805","tarball":"https://registry.npmjs.org/@solana/keychain-fordefi/-/keychain-fordefi-2.0.0-beta.1.tgz","fileCount":32,"integrity":"sha512-IoGqQMoKHPzu92FcatH9B1rCbZTMdh380ooy/uTE1xRB7VfO9H5K+XJ8E8pLxc8BXKhg8HzPVQLo4rnDPklWkA==","signatures":[{"sig":"MEQCIHNwIfZWv2YoAg3U0mf8sBft02NhN0IL04fq72vMS/kzAiB0TggOWkTOb1VGrQL5nNkx53cuvdPGP9fOTEUiTPQphA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@solana%2fkeychain-fordefi@2.0.0-beta.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":279142},"main":"./dist/index.js","type":"module","_from":"file:.npm-pack/solana-keychain-fordefi-2.0.0-beta.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"tsc --build","clean":"rm -rf dist *.tsbuildinfo","test:unit":"vitest run --config ../../vitest.config.unit.ts","typecheck":"tsc --noEmit","test:watch":"vitest","test:watch:unit":"vitest --config ../../vitest.config.unit.ts","test:integration":"vitest run --config ../../vitest.config.integration.ts","test:treeshakability":"agadoo dist/index.js","test:watch:integration":"vitest --config ../../vitest.config.integration.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f7008c39-83e7-4b53-a59e-ff5530c7d4e5"}},"_resolved":"/home/runner/work/solana-keychain/solana-keychain/typescript/.npm-pack/solana-keychain-fordefi-2.0.0-beta.1.tgz","_integrity":"sha512-IoGqQMoKHPzu92FcatH9B1rCbZTMdh380ooy/uTE1xRB7VfO9H5K+XJ8E8pLxc8BXKhg8HzPVQLo4rnDPklWkA==","repository":{"url":"git+https://github.com/solana-foundation/solana-keychain.git","type":"git"},"_npmVersion":"11.17.0","description":"Fordefi MPC signer for Solana transactions","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","dependencies":{"@solana/keychain-core":"2.0.0-beta.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"dotenv":"^17.4.2","@solana/kit":"8.0.0","@solana/keys":"8.0.0","@solana/signers":"8.0.0","@solana/addresses":"8.0.0","@solana/transactions":"8.0.0","@solana-program/system":"^0.13.0","@solana/codecs-strings":"8.0.0","@solana/keychain-test-utils":"2.0.0-beta.1","@solana/transaction-messages":"8.0.0"},"peerDependencies":{"@solana/keys":">=8.0.0","@solana/signers":">=8.0.0","@solana/addresses":">=8.0.0","@solana/transactions":">=8.0.0","@solana/codecs-strings":">=8.0.0","@solana/transaction-messages":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/keychain-fordefi_2.0.0-beta.1_1787847740612_0.12596156026098893","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"_id":"@solana/keychain-fordefi@2.0.0","bugs":{"url":"https://github.com/solana-foundation/solana-keychain/issues"},"dist":{"shasum":"d50be9e125453f1ff73096caaaafca3322914ed2","tarball":"https://registry.npmjs.org/@solana/keychain-fordefi/-/keychain-fordefi-2.0.0.tgz","fileCount":32,"integrity":"sha512-R9sKsaqeWlkXWbH9iOSMofQw4zmnjOJHev+BEm5u8R69bvz8YPIJb4WbSm2Vk2/pZJ/nOt1EskkevaVOcASKfQ==","signatures":[{"sig":"MEUCIF7QqWSbBUpSgOM38TBxX9YbUdHnREXJl44K/juepYZQAiEAo3LQ7D3+5nofzyfFA6LXwR51yp9nGC3d4CqNUQrCSA0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBTogZta5iiI5mqWGS3qSeZno4TNZ38PoTaOJsBPPnXRAiEA0yRgew5/2r+j+IPi9gWdLx0z1yGO/p5Mfalk5vKhywM="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@solana%2fkeychain-fordefi@2.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":347259},"main":"./dist/index.js","name":"@solana/keychain-fordefi","type":"module","_from":"file:.npm-pack/solana-keychain-fordefi-2.0.0.tgz","types":"./dist/index.d.ts","author":{"name":"Solana Foundation"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"license":"MIT","scripts":{"test":"vitest run","build":"tsc --build","clean":"rm -rf dist *.tsbuildinfo","test:unit":"vitest run --config ../../vitest.config.unit.ts","typecheck":"tsc --noEmit","test:watch":"vitest","test:watch:unit":"vitest --config ../../vitest.config.unit.ts","test:integration":"vitest run --config ../../vitest.config.integration.ts","test:treeshakability":"agadoo dist/index.js","test:watch:integration":"vitest --config ../../vitest.config.integration.ts"},"version":"2.0.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"f7008c39-83e7-4b53-a59e-ff5530c7d4e5"}},"homepage":"https://github.com/solana-foundation/solana-keychain#readme","keywords":["solana","signing","wallet","fordefi","mpc","custody"],"_resolved":"/home/runner/work/solana-keychain/solana-keychain/typescript/.npm-pack/solana-keychain-fordefi-2.0.0.tgz","_integrity":"sha512-R9sKsaqeWlkXWbH9iOSMofQw4zmnjOJHev+BEm5u8R69bvz8YPIJb4WbSm2Vk2/pZJ/nOt1EskkevaVOcASKfQ==","repository":{"url":"git+https://github.com/solana-foundation/solana-keychain.git","type":"git"},"_npmVersion":"11.19.0","description":"Fordefi MPC signer for Solana transactions","directories":{},"maintainers":[{"name":"solana-devs","email":"npm@solana.org"}],"sideEffects":false,"_nodeVersion":"24.21.0","dependencies":{"@solana/keychain-core":"2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"dotenv":"^17.4.2","@solana/kit":"8.3.0","@solana/keys":"8.3.0","@solana/signers":"8.3.0","@solana/addresses":"8.3.0","@solana/transactions":"8.3.0","@solana-program/system":"^0.13.0","@solana/codecs-strings":"8.3.0","@solana/keychain-test-utils":"2.0.0","@solana/transaction-messages":"8.3.0"},"peerDependencies":{"@solana/keys":">=8.1.0","@solana/signers":">=8.1.0","@solana/addresses":">=8.1.0","@solana/transactions":">=8.1.0","@solana/codecs-strings":">=8.1.0","@solana/transaction-messages":">=8.1.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/keychain-fordefi_2.0.0_1790868946795_0.7990933831485589"}}},"time":{"created":"2026-07-28T16:08:02.274Z","modified":"2026-10-01T15:35:54.998Z","0.0.0":"2026-07-28T16:08:02.589Z","2.0.0-beta.1":"2026-08-27T16:22:20.790Z","2.0.0":"2026-10-01T15:35:46.917Z"},"license":"MIT","maintainers":[{"name":"solana-devs","email":"npm@solana.org"}],"readme":"# @solana/keychain-fordefi\n\n[Fordefi](https://docs.fordefi.com/) MPC signer for Solana transactions, part of the [@solana/keychain](https://github.com/solana-foundation/solana-keychain) family.\n\n## Installation\n\n```bash\nnpm install @solana/keychain-fordefi\n```\n\n## Signing Modes\n\nThe signer supports three modes, determined by `chain` and `pushMode`. Kit classifies signers by method presence, so each mode exposes exactly one transaction entry point and none of the others:\n\n| Mode | Config | Shape | Entry point |\n|------|--------|-------|-------------|\n| Black box | `chain` unset | `FordefiBlackBoxSigner` | `signTransactions()` |\n| Native auto | `chain` set, `pushMode` omitted or `'auto'` | `FordefiNativeSigner` | `signAndSendTransactions()` |\n| Native manual | `chain` set, `pushMode: 'manual'` | `FordefiNativeManualSigner` | `modifyAndSignTransactions()` |\n\nAll three sign off-chain messages with `signMessages()`.\n\n### Native auto mode (recommended for on-chain use)\n\nSet `chain` to use Fordefi's native Solana transaction type. Fordefi may modify the transaction (e.g. updating the blockhash or adding compute budget instructions) and broadcasts it on-chain automatically. Use this with a **Solana vault**.\n\n> **Note:** Native auto mode is a Kit `TransactionSendingSigner` (`FordefiNativeSigner`, built on `SolanaSendingSigner` from `@solana/keychain-core`), because Fordefi may sign a different message than the one supplied by the caller and broadcasts it itself. Use `signAndSendTransactionMessageWithSigners()` or `signAndSendTransactions()`. Instances expose **no** `signTransactions`: Kit classifies signers by method presence, so its absence is what routes the signer through Kit's sending flow. Message signing (`signMessages`) still works. Black-box instances are the mirror image: `signTransactions` and no `signAndSendTransactions`.\n\n```typescript\nimport { createFordefiSigner } from '@solana/keychain-fordefi';\nimport { signAndSendTransactionMessageWithSigners } from '@solana/signers';\n\nconst signer = await createFordefiSigner({\n    accessToken: process.env.FORDEFI_ACCESS_TOKEN!,\n    vaultId: process.env.FORDEFI_VAULT_ID!,\n    privateKeyPem: fs.readFileSync('./secret/private.pem', 'utf8'),\n    publicKey: process.env.FORDEFI_PUBLIC_KEY!,\n    chain: 'solana_devnet',\n    fee: { type: 'custom', priority_fee: '1000' },\n});\n\nconst transactionSignature = await signAndSendTransactionMessageWithSigners(transactionMessage);\n```\n\nNative auto-broadcast currently supports transactions whose only required signer is the configured Fordefi vault. Transactions requiring additional signers are rejected before submission until the integration forwards their partial signatures through Fordefi's `details.signatures` field.\n\n### Native manual mode\n\nAdd `pushMode: 'manual'` to the native config. Fordefi still parses the transaction, so its policy engine and approval UI apply, but it signs **without** broadcasting: you own submission, and additional required signers are supported, which native auto rejects.\n\nManual mode is a Kit `TransactionModifyingSigner` (`FordefiNativeManualSigner`, built on `SolanaModifyingSigner`). `modifyAndSignTransactions()` returns the transaction Fordefi signed, which **replaces** the one you submitted: continue from the returned value so every downstream signer signs the message the Fordefi signature covers.\n\n```typescript\nimport { createFordefiSigner } from '@solana/keychain-fordefi';\n\nconst signer = await createFordefiSigner({\n    accessToken: process.env.FORDEFI_ACCESS_TOKEN!,\n    vaultId: process.env.FORDEFI_VAULT_ID!,\n    privateKeyPem: fs.readFileSync('./secret/private.pem', 'utf8'),\n    publicKey: process.env.FORDEFI_PUBLIC_KEY!,\n    chain: 'solana_devnet',\n    pushMode: 'manual',\n});\n\nconst [signedTransaction] = await signer.modifyAndSignTransactions([transaction]);\nawait rpc.sendTransaction(getBase64EncodedWireTransaction(signedTransaction), { encoding: 'base64' }).send();\n```\n\nRequirements and caveats:\n\n- Fordefi may rewrite the message: at minimum the recent blockhash, and it manages the Compute Budget fee instructions, so a compute-unit limit or price you set yourself may not survive. What changed is **not** diffed, so inspect the result before broadcasting if its contents matter to you.\n- The returned signature is verified with ed25519 against the message Fordefi returned, at the vault's required-signer position. A mismatch fails and is never handed back.\n- Fordefi refreshes the blockhash but does not report its `lastValidBlockHeight`, so a refreshed lifetime carries Kit's `U64_MAX` placeholder; broadcast promptly rather than relying on local expiry detection.\n- The create carries an `x-idempotence-id` derived from the message bytes under the push mode, chain, vault and fee it was submitted with, so resending the same bytes on the same terms reuses the Fordefi transaction instead of creating a second one, and cannot collide with a create made on other terms, such as an auto create that did broadcast them.\n\n### Black box mode\n\nOmit `chain` to use Fordefi's `black_box_signature` type. Fordefi signs the raw bytes as-is and does **not** broadcast. The caller is responsible for assembling and submitting the transaction. Use this with a **black box vault**.\n\n```typescript\nconst signer = await createFordefiSigner({\n    accessToken: process.env.FORDEFI_ACCESS_TOKEN!,\n    vaultId: process.env.FORDEFI_BB_VAULT_ID!,\n    privateKeyPem: fs.readFileSync('./secret/private.pem', 'utf8'),\n    publicKey: process.env.FORDEFI_BB_PUBLIC_KEY!,\n});\n```\n\n## Configuration\n\n| Option | Required | Description |\n|--------|----------|-------------|\n| `accessToken` | Yes | Fordefi API bearer token |\n| `vaultId` | Yes | Fordefi vault UUID |\n| `privateKeyPem` | One of | PEM-encoded ECDSA P-256 private key for API request signing |\n| `requestSigner` | One of | Custom API-request signer (e.g. KMS/HSM). Provide exactly one of `privateKeyPem` or `requestSigner` |\n| `publicKey` | Yes | Solana public key of the vault (base58) |\n| `chain` | No | `'solana_mainnet'` or `'solana_devnet'` — enables native Solana mode |\n| `pushMode` | No | `'auto'` (default) or `'manual'`, i.e. whether Fordefi broadcasts. `'manual'` requires `chain` |\n| `fee` | No | Priority fee config for native mode (e.g. `{ type: 'custom', priority_fee: '1000' }`) |\n| `apiBaseUrl` | No | API base URL (default: `https://api.fordefi.com`) |\n| `pollIntervalMs` | No | Polling interval in ms (default: 2000) |\n| `maxPollAttempts` | No | Positive integer max polling attempts (default: 50) |\n| `requestDelayMs` | No | Delay between requests in ms (default: 0). Native modes batch sequentially, so this is the gap between items |\n| `requestTimeoutMs` | No | Per-request HTTP timeout in ms (default: 30000) |\n\n### Custom API-request signer (KMS/HSM)\n\nFordefi authenticates every POST with a request-level signature over\n`{path}|{timestamp}|{body}` (ECDSA P-256, SHA-256, DER, base64). By default this is\ncomputed locally from `privateKeyPem`. To keep that key in a KMS/HSM instead, implement\n`FordefiRequestSigner` and pass it as `requestSigner` — `privateKeyPem` is then omitted.\n`signRequest` must return base64 of the DER-encoded ECDSA P-256 signature over\n`SHA-256(payload)`, and may be sync or async (AWS KMS `Sign` with `ECDSA_SHA_256` already\nreturns a DER signature — just base64-encode it).\n\n```ts\nimport { createFordefiSigner, type FordefiRequestSigner } from '@solana/keychain-fordefi';\n\nconst kmsRequestSigner: FordefiRequestSigner = {\n    async signRequest(payload) {\n        // Sign SHA-256(payload) with your KMS (ECDSA P-256) and base64-encode the\n        // returned DER signature. `payload` is `{path}|{timestamp}|{body}`.\n        return await signWithKms(payload);\n    },\n};\n\nconst signer = await createFordefiSigner({\n    accessToken: process.env.FORDEFI_ACCESS_TOKEN!,\n    vaultId: process.env.FORDEFI_VAULT_ID!,\n    publicKey: process.env.FORDEFI_PUBLIC_KEY!,\n    requestSigner: kmsRequestSigner, // instead of privateKeyPem\n});\n```\n\n## Integration Tests\n\n**`fordefi-signer.integration.test.ts`** exercises black box mode against the real Fordefi API and verifies the returned signatures with LiteSVM. It requires a **black box vault** (`FORDEFI_BB_VAULT_ID`, `FORDEFI_BB_PUBLIC_KEY`).\n\nRequired env vars (shared):\n\n```\nFORDEFI_ACCESS_TOKEN=<api-token>\nFORDEFI_PRIVATE_KEY_PEM=<pem-content>\n```\n\nBlack box vault:\n\n```\nFORDEFI_BB_VAULT_ID=<bb-vault-uuid>\nFORDEFI_BB_PUBLIC_KEY=<bb-vault-address>\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","description":"Fordefi MPC signer for Solana transactions","homepage":"https://github.com/solana-foundation/solana-keychain#readme","keywords":["solana","signing","wallet","fordefi","mpc","custody"],"repository":{"url":"git+https://github.com/solana-foundation/solana-keychain.git","type":"git"},"author":{"name":"Solana Foundation"},"bugs":{"url":"https://github.com/solana-foundation/solana-keychain/issues"}}