Skip to content

Commit 2ccfde5

Browse files
authored
Merge pull request #973 from LIT-Protocol/feat/get-derived-pubkey
Feat/get derived pubkey
2 parents 458d189 + 38a8e84 commit 2ccfde5

File tree

33 files changed

+670
-21
lines changed

33 files changed

+670
-21
lines changed

.changeset/two-mangos-lead.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@lit-protocol/lit-client': minor
3+
'@lit-protocol/contracts': minor
4+
'@lit-protocol/networks': minor
5+
'@lit-protocol/e2e': minor
6+
---
7+
8+
introduce `litClient.utils.getDerivedKeyId` - a little helper to resolve the Lit Action public key outside of the Action runtime

docs/guides/lit-action-sign-as-action.mdx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,21 @@ const { keccak256, arrayify } = ethers.utils;
6969
```
7070

7171
This approach keeps the derivation entirely within the Lit Action context. Because the public key depends only on the Action CID and signing scheme, you can rely on `Lit.Actions.getActionPublicKey` for a deterministic identity without needing to execute the Action externally first.
72+
73+
## Derive the Same Public Key from Client Code
74+
75+
If you prefer to resolve the Lit Action public key outside of the Action runtime - e.g., inside tests or other tooling—the SDK now exposes a helper that calls the on-chain PubkeyRouter contract.
76+
77+
```ts
78+
import { createLitClient } from "@lit-protocol/lit-client";
79+
import { nagaDev } from "@lit-protocol/networks";
80+
import { keccak256, stringToBytes } from "viem";
81+
82+
const litClient = await createLitClient({ network: nagaDev });
83+
const derivedKeyId = keccak256(stringToBytes(`lit_action_${actionIpfsCid}`));
84+
const actionPublicKey = await litClient.utils.getDerivedKeyId(derivedKeyId);
85+
86+
console.log("Derived Lit Action pubkey:", actionPublicKey);
87+
```
88+
89+
Under the hood, `getDerivedKeyId` routes through `PubkeyRouter.getDerivedPubkey`, passing the staking contract address and the default Naga key set (`naga-keyset1`) (will be dynamic in the future). This mirrors the same key derivation the nodes perform, letting you confirm identities or signatures without re-running the Lit Action.

docs/sdk/sdk-reference/lit-client/functions/createLitClient.mdx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,33 @@ Create a Viem-compatible account backed by a PKP.
10461046
</Expandable>
10471047
</ResponseField>
10481048

1049+
### utils.getDerivedKeyId
1050+
1051+
Resolve the uncompressed PKP public key for a given derived key identifier.
1052+
1053+
#### Parameters
1054+
1055+
<ResponseField name="derivedKeyId" type="string" required>
1056+
0x-prefixed bytes32 identifier (for example, <code>keccak256(stringToBytes(`lit_action_${ipfsCid}`))</code>).
1057+
</ResponseField>
1058+
1059+
#### Returns
1060+
1061+
<ResponseField name="result" type="Promise<string>">
1062+
0x-prefixed uncompressed public key as returned by the PubkeyRouter contract.
1063+
</ResponseField>
1064+
1065+
#### Example
1066+
1067+
```ts
1068+
import { keccak256, stringToBytes } from "viem";
1069+
1070+
const derivedKeyId = keccak256(stringToBytes(`lit_action_${ipfsCid}`));
1071+
const derivedPubkey = await litClient.utils.getDerivedKeyId(derivedKeyId);
1072+
```
1073+
1074+
> Note: this helper currently calls `PubkeyRouter.getDerivedPubkey` with the default Naga key set (`naga-keyset1`). See the [Derive Lit Action Public Keys guide](../../../../guides/lit-action-sign-as-action) for an end-to-end workflow.
1075+
10491076
### getChainConfig
10501077

10511078
Returns the chain configuration for the current network.
@@ -1074,4 +1101,4 @@ Stop background state updates and release resources.
10741101
none
10751102

10761103
#### Returns
1077-
void
1104+
void

packages/contracts/dist/dev/develop.cjs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15431,11 +15431,6 @@ module.exports = {
1543115431
"name": "CallerNotOwner",
1543215432
"type": "error"
1543315433
},
15434-
{
15435-
"inputs": [],
15436-
"name": "MustBeLessThan100",
15437-
"type": "error"
15438-
},
1543915434
{
1544015435
"inputs": [],
1544115436
"name": "MustBeNonzero",

packages/contracts/dist/dev/develop.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15429,11 +15429,6 @@ export const develop = {
1542915429
"name": "CallerNotOwner",
1543015430
"type": "error"
1543115431
},
15432-
{
15433-
"inputs": [],
15434-
"name": "MustBeLessThan100",
15435-
"type": "error"
15436-
},
1543715432
{
1543815433
"inputs": [],
1543915434
"name": "MustBeNonzero",

packages/contracts/dist/dev/develop.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15429,11 +15429,6 @@
1542915429
"name": "CallerNotOwner",
1543015430
"type": "error"
1543115431
},
15432-
{
15433-
"inputs": [],
15434-
"name": "MustBeLessThan100",
15435-
"type": "error"
15436-
},
1543715432
{
1543815433
"inputs": [],
1543915434
"name": "MustBeNonzero",

packages/contracts/dist/dev/develop.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15429,11 +15429,6 @@ export const develop = {
1542915429
"name": "CallerNotOwner",
1543015430
"type": "error"
1543115431
},
15432-
{
15433-
"inputs": [],
15434-
"name": "MustBeLessThan100",
15435-
"type": "error"
15436-
},
1543715432
{
1543815433
"inputs": [],
1543915434
"name": "MustBeNonzero",

packages/contracts/dist/signatures/datil-dev.cjs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,30 @@ const signatures = {
673673
"stateMutability": "view",
674674
"type": "function"
675675
},
676+
"getDerivedPubkey": {
677+
"inputs": [
678+
{
679+
"internalType": "address",
680+
"name": "stakingContract",
681+
"type": "address"
682+
},
683+
{
684+
"internalType": "bytes32",
685+
"name": "derivedKeyId",
686+
"type": "bytes32"
687+
}
688+
],
689+
"name": "getDerivedPubkey",
690+
"outputs": [
691+
{
692+
"internalType": "bytes",
693+
"name": "",
694+
"type": "bytes"
695+
}
696+
],
697+
"stateMutability": "view",
698+
"type": "function"
699+
},
676700
"getEthAddress": {
677701
"inputs": [
678702
{

packages/contracts/dist/signatures/datil-dev.d.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,30 @@ export const signatures = {
673673
"stateMutability": "view",
674674
"type": "function"
675675
},
676+
"getDerivedPubkey": {
677+
"inputs": [
678+
{
679+
"internalType": "address",
680+
"name": "stakingContract",
681+
"type": "address"
682+
},
683+
{
684+
"internalType": "bytes32",
685+
"name": "derivedKeyId",
686+
"type": "bytes32"
687+
}
688+
],
689+
"name": "getDerivedPubkey",
690+
"outputs": [
691+
{
692+
"internalType": "bytes",
693+
"name": "",
694+
"type": "bytes"
695+
}
696+
],
697+
"stateMutability": "view",
698+
"type": "function"
699+
},
676700
"getEthAddress": {
677701
"inputs": [
678702
{

packages/contracts/dist/signatures/datil-dev.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,30 @@ export const signatures = {
673673
"stateMutability": "view",
674674
"type": "function"
675675
},
676+
"getDerivedPubkey": {
677+
"inputs": [
678+
{
679+
"internalType": "address",
680+
"name": "stakingContract",
681+
"type": "address"
682+
},
683+
{
684+
"internalType": "bytes32",
685+
"name": "derivedKeyId",
686+
"type": "bytes32"
687+
}
688+
],
689+
"name": "getDerivedPubkey",
690+
"outputs": [
691+
{
692+
"internalType": "bytes",
693+
"name": "",
694+
"type": "bytes"
695+
}
696+
],
697+
"stateMutability": "view",
698+
"type": "function"
699+
},
676700
"getEthAddress": {
677701
"inputs": [
678702
{

0 commit comments

Comments
 (0)