Skip to content

Commit 628ba81

Browse files
feat: Add getVincentWrappedKeysAccs() to contracts-sdk
- Removed intended-to-be-private ABI export, contract address, and `getPkpTokenId()` method
1 parent bac33dc commit 628ba81

File tree

4 files changed

+156
-4
lines changed

4 files changed

+156
-4
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
contracts-sdk: major
3+
---
4+
5+
### Added `getVincentWrappedKeysAccs()`
6+
7+
- Returns an array of access control conditions that are used to encrypt/decrypt Vincent delegated wrapped keys.
8+
9+
### Removed `COMBINED_ABI` and `getPkpTokenId` exports
10+
11+
- These were intended to be internal-only details of the vincent-contracts-sdk

packages/libs/contracts-sdk/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
"devDependencies": {
1919
"@dotenvx/dotenvx": "^1.44.2",
2020
"@lit-protocol/auth-helpers": "^7.2.3",
21-
"@lit-protocol/constants": "^7.2.3",
21+
"@lit-protocol/constants": "^7.3.1",
2222
"@lit-protocol/contracts-sdk": "^7.2.3",
2323
"@lit-protocol/lit-node-client": "^7.2.3",
2424
"@lit-protocol/pkp-ethers": "^7.2.3",
25+
"@lit-protocol/types": "^7.2.3",
2526
"@openzeppelin/contracts": "5.3.0",
2627
"@types/jest": "^29.5.12",
2728
"jest": "^29.5.0",

packages/libs/contracts-sdk/src/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,4 @@ export { getTestClient, clientFromContract, getClient } from './contractClient';
4343

4444
export { createContract } from './utils';
4545

46-
export { getPkpTokenId } from './utils/pkpInfo';
47-
48-
export { VINCENT_DIAMOND_CONTRACT_ADDRESS_PROD, COMBINED_ABI } from './constants';
46+
export { getVincentWrappedKeysAccs } from './internal/wrapped-keys/getVincentWrappedKeysAccs';
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import { ethers } from 'ethers';
2+
3+
import type { AccsEVMParams, EvmContractConditions } from '@lit-protocol/types';
4+
5+
import { LIT_NETWORK, LIT_RPC } from '@lit-protocol/constants';
6+
import { LitContracts } from '@lit-protocol/contracts-sdk';
7+
8+
import { COMBINED_ABI, VINCENT_DIAMOND_CONTRACT_ADDRESS_PROD } from '../../constants';
9+
import { getPkpTokenId } from '../../utils/pkpInfo';
10+
11+
const CHAIN_YELLOWSTONE = 'yellowstone' as const;
12+
13+
/**
14+
* Creates access control condition to validate Vincent delegatee and platform user authorization
15+
* via the Vincent registry contract's isDelegateePermitted method and the PKP NFT contract's ownerOf method
16+
*
17+
* Creates access control conditions for both the delegatee and the platform user.
18+
* Delegatee authorization is validated by the Vincent registry contract's isDelegateePermitted method.
19+
* Platform user authorization is validated by validating the owner of the delegator PKP token is the requester by checking
20+
* the Lit PKP NFT contract's ownerOf method.
21+
*
22+
* @param delegatorAddress - The address of the delegator
23+
*
24+
* @returns EvmContractConditions - Access control conditions authorizing a valid delegatee OR a platform user that is the owner of the delegator's PKP token
25+
*/
26+
export async function getVincentWrappedKeysAccs({
27+
delegatorAddress,
28+
}: {
29+
delegatorAddress: string;
30+
}): Promise<EvmContractConditions> {
31+
if (!ethers.utils.isAddress(delegatorAddress)) {
32+
throw new Error(`delegatorAddress is not a valid Ethereum Address: ${delegatorAddress}`);
33+
}
34+
35+
const delegatorPkpTokenId = (
36+
await getPkpTokenId({
37+
pkpEthAddress: delegatorAddress,
38+
signer: ethers.Wallet.createRandom().connect(
39+
new ethers.providers.StaticJsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE),
40+
), // Read only; signer identity is irrelevant in this code path :),
41+
})
42+
).toString();
43+
44+
return Promise.all([
45+
getDelegateeAccessControlConditions({
46+
delegatorPkpTokenId,
47+
}),
48+
Promise.resolve({ operator: 'or' }),
49+
getPlatformUserAccessControlConditions({
50+
delegatorPkpTokenId,
51+
}),
52+
]);
53+
}
54+
55+
async function getDelegateeAccessControlConditions({
56+
delegatorPkpTokenId,
57+
}: {
58+
delegatorPkpTokenId: string;
59+
}): Promise<AccsEVMParams> {
60+
const contractInterface = new ethers.utils.Interface(COMBINED_ABI.fragments);
61+
const fragment = contractInterface.getFunction('isDelegateePermitted');
62+
63+
const functionAbi = {
64+
type: 'function',
65+
name: fragment.name,
66+
inputs: fragment.inputs.map((input) => ({
67+
name: input.name,
68+
type: input.type,
69+
})),
70+
outputs: fragment.outputs?.map((output) => ({
71+
name: output.name,
72+
type: output.type,
73+
})),
74+
stateMutability: fragment.stateMutability,
75+
};
76+
77+
return {
78+
contractAddress: VINCENT_DIAMOND_CONTRACT_ADDRESS_PROD,
79+
chain: CHAIN_YELLOWSTONE,
80+
functionAbi,
81+
functionName: 'isDelegateePermitted',
82+
functionParams: [':userAddress', delegatorPkpTokenId, ':currentActionIpfsId'],
83+
returnValueTest: {
84+
key: 'isPermitted',
85+
comparator: '=',
86+
value: 'true',
87+
},
88+
};
89+
}
90+
91+
/**
92+
* Delegated wrapped keys access control condition is 'the owner of the PKP may decrypt this'
93+
* - e.g. the Vincent 'user PKP' can decrypt the wrapped keys for all of their agent PKPs
94+
*
95+
* This contrasts from the original wrapped keys access control condition, which was 'the PKP itself may decrypt this'
96+
*
97+
* @param delegatorPkpTokenId
98+
*/
99+
async function getPlatformUserAccessControlConditions({
100+
delegatorPkpTokenId,
101+
}: {
102+
delegatorPkpTokenId: string;
103+
}): Promise<AccsEVMParams> {
104+
const contractAddresses = await LitContracts.getContractAddresses(
105+
LIT_NETWORK.Datil,
106+
new ethers.providers.StaticJsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE),
107+
);
108+
109+
const pkpNftContractInfo: { address: string; abi: any[] } = contractAddresses.PKPNFT;
110+
if (!pkpNftContractInfo) {
111+
throw new Error('PKP NFT contract address not found for Datil network');
112+
}
113+
114+
return {
115+
contractAddress: pkpNftContractInfo.address,
116+
chain: CHAIN_YELLOWSTONE,
117+
functionAbi: {
118+
type: 'function',
119+
name: 'ownerOf',
120+
inputs: [
121+
{
122+
name: 'tokenId',
123+
type: 'uint256',
124+
},
125+
],
126+
outputs: [
127+
{
128+
name: '',
129+
type: 'address',
130+
},
131+
],
132+
stateMutability: 'view',
133+
},
134+
functionName: 'ownerOf',
135+
functionParams: [delegatorPkpTokenId],
136+
returnValueTest: {
137+
key: '',
138+
comparator: '=',
139+
value: ':userAddress',
140+
},
141+
};
142+
}

0 commit comments

Comments
 (0)