@equalfi/ski 0.1.0
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 +31 -0
- package/bin/cli.js +123 -0
- package/package.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @equalfi/ski
|
|
2
|
+
|
|
3
|
+
Interactive Session Key Installer for EqualFi.
|
|
4
|
+
|
|
5
|
+
## Install & Run
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm dlx @equalfi/ski
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
- Prompts for Position NFT id and Validation Entity ID
|
|
13
|
+
- Generates a fresh session EOA
|
|
14
|
+
- Stores encrypted keystore at `~/.openclaw/keys/equalfi/<label>.json`
|
|
15
|
+
- Stores the password in your OS keychain (one prompt)
|
|
16
|
+
- Prints the session key address to paste into the UI
|
|
17
|
+
|
|
18
|
+
## Notes
|
|
19
|
+
- Default label is `position-<tokenId>`
|
|
20
|
+
- If the key already exists, it asks before overwriting
|
|
21
|
+
|
|
22
|
+
## Output example
|
|
23
|
+
```
|
|
24
|
+
✅ Session key created
|
|
25
|
+
Address: 0xabc...
|
|
26
|
+
Label: position-1
|
|
27
|
+
Entity: 7
|
|
28
|
+
Stored: ~/.openclaw/keys/equalfi/position-1.json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then paste the address into the EqualFi UI Session Key Address field and click **Install Session Key Module**.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs/promises');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
const prompts = require('prompts');
|
|
8
|
+
const keytar = require('keytar');
|
|
9
|
+
const { Wallet } = require('ethers');
|
|
10
|
+
|
|
11
|
+
const SERVICE = 'equalfi-ski';
|
|
12
|
+
const SKILL_ID = 'equalfi';
|
|
13
|
+
const DEFAULT_ENTITY_ID = 7;
|
|
14
|
+
|
|
15
|
+
const resolvePaths = (label) => {
|
|
16
|
+
const baseDir = path.join(os.homedir(), '.openclaw', 'keys', SKILL_ID);
|
|
17
|
+
return {
|
|
18
|
+
baseDir,
|
|
19
|
+
keystorePath: path.join(baseDir, `${label}.json`),
|
|
20
|
+
metaPath: path.join(baseDir, `${label}.meta.json`),
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const keychainAccount = (label) => `session-key:${SKILL_ID}:${label}`;
|
|
25
|
+
|
|
26
|
+
async function ensureDir(dir) {
|
|
27
|
+
await fs.mkdir(dir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function fileExists(p) {
|
|
31
|
+
try {
|
|
32
|
+
await fs.access(p);
|
|
33
|
+
return true;
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function main() {
|
|
40
|
+
const response = await prompts([
|
|
41
|
+
{
|
|
42
|
+
type: 'number',
|
|
43
|
+
name: 'tokenId',
|
|
44
|
+
message: 'Position NFT id (for label)',
|
|
45
|
+
validate: (v) => (Number.isFinite(v) && v > 0 ? true : 'Enter a positive integer'),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'number',
|
|
49
|
+
name: 'entityId',
|
|
50
|
+
message: 'Validation Entity ID',
|
|
51
|
+
initial: DEFAULT_ENTITY_ID,
|
|
52
|
+
validate: (v) => (Number.isFinite(v) && v >= 0 ? true : 'Enter a non-negative integer'),
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
if (response.tokenId === undefined) {
|
|
57
|
+
console.log('Cancelled.');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const label = `position-${response.tokenId}`;
|
|
62
|
+
const entityId = Number(response.entityId ?? DEFAULT_ENTITY_ID);
|
|
63
|
+
|
|
64
|
+
const { baseDir, keystorePath, metaPath } = resolvePaths(label);
|
|
65
|
+
await ensureDir(baseDir);
|
|
66
|
+
|
|
67
|
+
if (await fileExists(keystorePath)) {
|
|
68
|
+
const confirm = await prompts({
|
|
69
|
+
type: 'confirm',
|
|
70
|
+
name: 'overwrite',
|
|
71
|
+
message: `Key for ${label} already exists. Overwrite?`,
|
|
72
|
+
initial: false,
|
|
73
|
+
});
|
|
74
|
+
if (!confirm.overwrite) {
|
|
75
|
+
console.log('Aborted.');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const wallet = Wallet.createRandom();
|
|
81
|
+
const password = crypto.randomBytes(32).toString('hex');
|
|
82
|
+
const keystore = await wallet.encrypt(password);
|
|
83
|
+
|
|
84
|
+
await fs.writeFile(keystorePath, keystore);
|
|
85
|
+
await fs.writeFile(
|
|
86
|
+
metaPath,
|
|
87
|
+
JSON.stringify(
|
|
88
|
+
{
|
|
89
|
+
address: wallet.address,
|
|
90
|
+
chainId: null,
|
|
91
|
+
skillId: SKILL_ID,
|
|
92
|
+
agentLabel: label,
|
|
93
|
+
positionTokenId: response.tokenId,
|
|
94
|
+
entityId,
|
|
95
|
+
createdAt: new Date().toISOString(),
|
|
96
|
+
keychainService: SERVICE,
|
|
97
|
+
keychainAccount: keychainAccount(label),
|
|
98
|
+
},
|
|
99
|
+
null,
|
|
100
|
+
2
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
await keytar.setPassword(SERVICE, keychainAccount(label), password);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error('Failed to store key in OS keychain:', err?.message || err);
|
|
108
|
+
console.error('Keystore saved, but you must secure the password manually.');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log('\n✅ Session key created');
|
|
113
|
+
console.log(`Address: ${wallet.address}`);
|
|
114
|
+
console.log(`Label: ${label}`);
|
|
115
|
+
console.log(`Entity: ${entityId}`);
|
|
116
|
+
console.log(`Stored: ${keystorePath}`);
|
|
117
|
+
console.log('\nPaste the address into the UI session key field and install the module/policy.');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
main().catch((err) => {
|
|
121
|
+
console.error(err);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@equalfi/ski",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "EqualFi Session Key Installer (interactive CLI)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ski": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"ethers": "^6.13.5",
|
|
18
|
+
"keytar": "^7.9.0",
|
|
19
|
+
"prompts": "^2.4.2"
|
|
20
|
+
}
|
|
21
|
+
}
|