@prktsol/prkt 1.0.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/.env.devnet.all-protocols.example +18 -0
- package/.env.devnet.autonomous.example +16 -0
- package/.env.devnet.jupiter.example +16 -0
- package/.env.devnet.kamino.example +17 -0
- package/.env.devnet.marinade.example +16 -0
- package/.env.devnet.orca.example +16 -0
- package/.env.devnet.raydium.example +17 -0
- package/.env.example +32 -0
- package/ARCHITECTURE.md +159 -0
- package/CLI.md +509 -0
- package/CLI_QUICKSTART.md +108 -0
- package/COMPATIBILITY.md +103 -0
- package/DEVNET_PROTOCOL_ADDRESSES.md +72 -0
- package/README.md +339 -0
- package/dist/agent/AgentManager.js +166 -0
- package/dist/agent/AgentRuntime.js +92 -0
- package/dist/agent/DecisionEngine.js +95 -0
- package/dist/agent/MockPriceFeed.js +13 -0
- package/dist/agent/intents/types.js +2 -0
- package/dist/agent/new-index.js +17 -0
- package/dist/agent/policyFactory.js +54 -0
- package/dist/agent/registry/AgentRegistry.js +16 -0
- package/dist/agent/runner/AgentRunner.js +266 -0
- package/dist/agent/strategies/MemoHeartbeatStrategy.js +15 -0
- package/dist/agent/strategies/SimpleScriptedTransferStrategy.js +27 -0
- package/dist/agent/strategies/TokenRebalancerStrategy.js +35 -0
- package/dist/agent/strategies/TreasuryDistributorStrategy.js +29 -0
- package/dist/agent/strategies/UniversalDeFiStrategy.js +19 -0
- package/dist/agent/types/AgentContext.js +2 -0
- package/dist/cli/index.js +1159 -0
- package/dist/cli/services/activityStore.js +42 -0
- package/dist/cli/services/agentRegistry.js +123 -0
- package/dist/cli/services/agentRuntime.js +55 -0
- package/dist/cli/services/storagePaths.js +64 -0
- package/dist/cli/services/strategyFactory.js +66 -0
- package/dist/cli/services/walletCrypto.js +120 -0
- package/dist/cli/services/walletRegistry.js +145 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/utils/completion.js +62 -0
- package/dist/cli/utils/output.js +44 -0
- package/dist/config/agentPolicies.js +37 -0
- package/dist/config/env.js +249 -0
- package/dist/config/policyPresets.js +105 -0
- package/dist/core/balances/BalanceService.js +34 -0
- package/dist/core/funding/DevnetFundingService.js +105 -0
- package/dist/core/idempotency/ExecutionIdempotencyGuard.js +100 -0
- package/dist/core/index.js +19 -0
- package/dist/core/rpc/RpcClient.js +45 -0
- package/dist/core/rpc/RpcFailoverClient.js +97 -0
- package/dist/core/tokens/TokenService.js +75 -0
- package/dist/core/transactions/PostTransactionVerifier.js +103 -0
- package/dist/core/transactions/TransactionService.js +104 -0
- package/dist/core/types/services.js +2 -0
- package/dist/core/wallet/WalletManager.js +120 -0
- package/dist/defi/DeFiCoordinator.js +93 -0
- package/dist/defi/DeFiExecutor.js +29 -0
- package/dist/defi/DeFiPolicyGuard.js +31 -0
- package/dist/defi/adapters/JupiterAdapter.js +25 -0
- package/dist/defi/adapters/KaminoAdapter.js +50 -0
- package/dist/defi/adapters/MarinadeAdapter.js +25 -0
- package/dist/defi/adapters/RaydiumAdapter.js +45 -0
- package/dist/defi/kamino/kaminoInstructionCompat.js +24 -0
- package/dist/defi/kamino/kaminoLiveConfig.js +60 -0
- package/dist/defi/kamino/loadKaminoMarketWithFallback.js +68 -0
- package/dist/defi/lp/LpInstructionBuilder.js +2 -0
- package/dist/defi/lp/RaydiumLpInstructionBuilder.js +100 -0
- package/dist/defi/lp/raydiumDevnetConfig.js +62 -0
- package/dist/defi/protocols.js +29 -0
- package/dist/defi/types.js +2 -0
- package/dist/defi/universal/UniversalDeFiOrchestrator.js +126 -0
- package/dist/defi/universal/adapters.js +73 -0
- package/dist/defi/universal/index.js +5 -0
- package/dist/defi/universal/liveExecutors.js +394 -0
- package/dist/defi/universal/types.js +2 -0
- package/dist/demo/scenarios/multiAgentDevnetScenario.js +170 -0
- package/dist/demo/scripts/runMultiAgentDevnetDemo.js +17 -0
- package/dist/dex/JupiterSwapClient.js +59 -0
- package/dist/dex/SwapExecutor.js +52 -0
- package/dist/index.js +22 -0
- package/dist/kora/KoraRpcClient.js +60 -0
- package/dist/kora/KoraSigner.js +57 -0
- package/dist/kora/gaslessDemo.js +18 -0
- package/dist/policy/PolicyGuard.js +158 -0
- package/dist/policy/emergencyLock.js +164 -0
- package/dist/policy/engine/PolicyEngine.js +237 -0
- package/dist/policy/errors.js +10 -0
- package/dist/policy/index.js +7 -0
- package/dist/policy/sandbox/SandboxExecutor.js +77 -0
- package/dist/policy/types/policy.js +2 -0
- package/dist/scripts/devnetFunding.js +28 -0
- package/dist/scripts/devnetWalletPreflight.js +16 -0
- package/dist/scripts/localnetCheck.js +27 -0
- package/dist/scripts/managedAgentWallet.js +81 -0
- package/dist/scripts/mode.js +6 -0
- package/dist/scripts/releaseReadiness.js +93 -0
- package/dist/scripts/runAgentUniversalDeFi.js +115 -0
- package/dist/scripts/runAutonomousAgentWalletDevnet.js +154 -0
- package/dist/scripts/runAutonomousPortfolioDevnet.js +390 -0
- package/dist/scripts/runBorrowStrategy.js +35 -0
- package/dist/scripts/runDeFiSuite.js +41 -0
- package/dist/scripts/runDemoRehearsal.js +111 -0
- package/dist/scripts/runDevnetWalletDemo.js +53 -0
- package/dist/scripts/runGaslessMemo.js +23 -0
- package/dist/scripts/runGaslessWalletDemo.js +60 -0
- package/dist/scripts/runKaminoDevnet.js +109 -0
- package/dist/scripts/runLpStrategy.js +32 -0
- package/dist/scripts/runMarinadeDevnet.js +97 -0
- package/dist/scripts/runOrcaLpDevnet.js +208 -0
- package/dist/scripts/runRaydiumLpDevnet.js +95 -0
- package/dist/scripts/runReleaseReadiness.js +22 -0
- package/dist/scripts/runStakeStrategy.js +33 -0
- package/dist/scripts/runStressTest.js +41 -0
- package/dist/scripts/runTradeLoop.js +53 -0
- package/dist/scripts/runUniversalDeFiDemo.js +84 -0
- package/dist/scripts/runYieldStrategy.js +33 -0
- package/dist/scripts/runtimeFactory.js +27 -0
- package/dist/scripts/shared.js +24 -0
- package/dist/scripts/simulateAttack.js +40 -0
- package/dist/scripts/simulateSwarm.js +106 -0
- package/dist/simulation/attack.js +30 -0
- package/dist/solana/programs.js +9 -0
- package/dist/spl/TokenWallet.js +65 -0
- package/dist/types/policy.js +2 -0
- package/dist/wallet/WalletManager.js +5 -0
- package/package.json +99 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ActivityStore = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const storagePaths_1 = require("./storagePaths");
|
|
10
|
+
class ActivityStore {
|
|
11
|
+
append(record) {
|
|
12
|
+
const payload = this.read();
|
|
13
|
+
payload.activities.push(record);
|
|
14
|
+
this.write(payload);
|
|
15
|
+
}
|
|
16
|
+
list(limit = 100) {
|
|
17
|
+
const activities = this.read().activities;
|
|
18
|
+
return activities.slice(Math.max(activities.length - limit, 0));
|
|
19
|
+
}
|
|
20
|
+
listByAgent(agent, limit = 100) {
|
|
21
|
+
return this.list(limit).filter((entry) => entry.agent === agent);
|
|
22
|
+
}
|
|
23
|
+
read() {
|
|
24
|
+
const storePath = (0, storagePaths_1.resolveCliDataPath)("cli-activity.json");
|
|
25
|
+
if (!(0, fs_1.existsSync)(storePath)) {
|
|
26
|
+
return {
|
|
27
|
+
activities: []
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const raw = (0, fs_1.readFileSync)(storePath, "utf8");
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
return {
|
|
33
|
+
activities: parsed.activities ?? []
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
write(payload) {
|
|
37
|
+
const storePath = (0, storagePaths_1.resolveCliDataPath)("cli-activity.json");
|
|
38
|
+
(0, fs_1.mkdirSync)(path_1.default.dirname(storePath), { recursive: true, mode: 0o700 });
|
|
39
|
+
(0, fs_1.writeFileSync)(storePath, JSON.stringify(payload, null, 2), { mode: 0o600 });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.ActivityStore = ActivityStore;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AgentRegistryStore = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const walletRegistry_1 = require("./walletRegistry");
|
|
10
|
+
const storagePaths_1 = require("./storagePaths");
|
|
11
|
+
const policyPresets_1 = require("../../config/policyPresets");
|
|
12
|
+
class AgentRegistryStore {
|
|
13
|
+
walletRegistry;
|
|
14
|
+
constructor(walletRegistry = new walletRegistry_1.WalletRegistry()) {
|
|
15
|
+
this.walletRegistry = walletRegistry;
|
|
16
|
+
}
|
|
17
|
+
list() {
|
|
18
|
+
return this.read().agents.slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
19
|
+
}
|
|
20
|
+
find(name) {
|
|
21
|
+
return this.read().agents.find((agent) => agent.name === name);
|
|
22
|
+
}
|
|
23
|
+
ensureForWallet(walletName) {
|
|
24
|
+
const existing = this.find(walletName);
|
|
25
|
+
if (existing) {
|
|
26
|
+
return existing;
|
|
27
|
+
}
|
|
28
|
+
const wallet = this.walletRegistry.find(walletName);
|
|
29
|
+
if (!wallet) {
|
|
30
|
+
throw new Error(`Cannot create agent for wallet '${walletName}': wallet not found.`);
|
|
31
|
+
}
|
|
32
|
+
const record = {
|
|
33
|
+
createdAtIso: new Date().toISOString(),
|
|
34
|
+
name: walletName,
|
|
35
|
+
policyMode: "sandbox",
|
|
36
|
+
policyPreset: policyPresets_1.DEFAULT_POLICY_PRESET,
|
|
37
|
+
status: "active",
|
|
38
|
+
strategy: "memo-heartbeat",
|
|
39
|
+
walletName
|
|
40
|
+
};
|
|
41
|
+
this.upsert(record);
|
|
42
|
+
return record;
|
|
43
|
+
}
|
|
44
|
+
createAgent(input) {
|
|
45
|
+
const existing = this.find(input.agentId);
|
|
46
|
+
if (existing) {
|
|
47
|
+
throw new Error(`Agent '${input.agentId}' already exists.`);
|
|
48
|
+
}
|
|
49
|
+
const walletName = input.walletName ?? input.agentId;
|
|
50
|
+
const wallet = this.walletRegistry.find(walletName);
|
|
51
|
+
if (!wallet) {
|
|
52
|
+
throw new Error(`Cannot create agent '${input.agentId}': wallet '${walletName}' not found.`);
|
|
53
|
+
}
|
|
54
|
+
const record = {
|
|
55
|
+
createdAtIso: new Date().toISOString(),
|
|
56
|
+
name: input.agentId,
|
|
57
|
+
ownerId: input.ownerId,
|
|
58
|
+
policyMode: "sandbox",
|
|
59
|
+
policyPreset: policyPresets_1.DEFAULT_POLICY_PRESET,
|
|
60
|
+
status: "active",
|
|
61
|
+
strategy: "memo-heartbeat",
|
|
62
|
+
walletName
|
|
63
|
+
};
|
|
64
|
+
this.upsert(record);
|
|
65
|
+
return record;
|
|
66
|
+
}
|
|
67
|
+
upsert(record) {
|
|
68
|
+
const registry = this.read();
|
|
69
|
+
const existingIndex = registry.agents.findIndex((agent) => agent.name === record.name);
|
|
70
|
+
if (existingIndex >= 0) {
|
|
71
|
+
registry.agents[existingIndex] = record;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
registry.agents.push(record);
|
|
75
|
+
}
|
|
76
|
+
this.write(registry);
|
|
77
|
+
return record;
|
|
78
|
+
}
|
|
79
|
+
patch(name, update) {
|
|
80
|
+
const existing = this.find(name);
|
|
81
|
+
if (!existing) {
|
|
82
|
+
throw new Error(`Agent '${name}' not found.`);
|
|
83
|
+
}
|
|
84
|
+
return this.upsert({
|
|
85
|
+
...existing,
|
|
86
|
+
...update
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
synchronizeWithWallets() {
|
|
90
|
+
for (const wallet of this.walletRegistry.list()) {
|
|
91
|
+
if (!this.find(wallet.name)) {
|
|
92
|
+
this.ensureForWallet(wallet.name);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return this.list();
|
|
96
|
+
}
|
|
97
|
+
read() {
|
|
98
|
+
const registryPath = (0, storagePaths_1.resolveCliDataPath)("cli-agents.json");
|
|
99
|
+
if (!(0, fs_1.existsSync)(registryPath)) {
|
|
100
|
+
return {
|
|
101
|
+
agents: []
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const raw = (0, fs_1.readFileSync)(registryPath, "utf8");
|
|
105
|
+
const parsed = JSON.parse(raw);
|
|
106
|
+
return {
|
|
107
|
+
agents: (parsed.agents ?? []).map((agent) => this.normalize(agent))
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
write(payload) {
|
|
111
|
+
const registryPath = (0, storagePaths_1.resolveCliDataPath)("cli-agents.json");
|
|
112
|
+
(0, fs_1.mkdirSync)(path_1.default.dirname(registryPath), { recursive: true, mode: 0o700 });
|
|
113
|
+
(0, fs_1.writeFileSync)(registryPath, JSON.stringify(payload, null, 2), { mode: 0o600 });
|
|
114
|
+
}
|
|
115
|
+
normalize(agent) {
|
|
116
|
+
return {
|
|
117
|
+
...agent,
|
|
118
|
+
ownerId: agent.ownerId,
|
|
119
|
+
policyPreset: agent.policyPreset ?? policyPresets_1.DEFAULT_POLICY_PRESET
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.AgentRegistryStore = AgentRegistryStore;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runAgentOnce = runAgentOnce;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const AgentRunner_1 = require("../../agent/runner/AgentRunner");
|
|
6
|
+
const env_1 = require("../../config/env");
|
|
7
|
+
const policyPresets_1 = require("../../config/policyPresets");
|
|
8
|
+
const BalanceService_1 = require("../../core/balances/BalanceService");
|
|
9
|
+
const RpcClient_1 = require("../../core/rpc/RpcClient");
|
|
10
|
+
const TokenService_1 = require("../../core/tokens/TokenService");
|
|
11
|
+
const TransactionService_1 = require("../../core/transactions/TransactionService");
|
|
12
|
+
const universal_1 = require("../../defi/universal");
|
|
13
|
+
const shared_1 = require("../../scripts/shared");
|
|
14
|
+
const walletRegistry_1 = require("./walletRegistry");
|
|
15
|
+
const strategyFactory_1 = require("./strategyFactory");
|
|
16
|
+
async function runAgentOnce(input) {
|
|
17
|
+
const walletRegistry = new walletRegistry_1.WalletRegistry();
|
|
18
|
+
const walletManager = walletRegistry.toWalletManager(input.agent.walletName);
|
|
19
|
+
const rpcClient = new RpcClient_1.RpcClient((0, env_1.getRpcUrl)(), "confirmed");
|
|
20
|
+
const tokenService = new TokenService_1.TokenService(rpcClient);
|
|
21
|
+
const transactionService = new TransactionService_1.TransactionService(rpcClient);
|
|
22
|
+
const balanceService = new BalanceService_1.BalanceService(rpcClient, tokenService);
|
|
23
|
+
const universalDeFi = new universal_1.UniversalDeFiOrchestrator({
|
|
24
|
+
koraSigner: (0, shared_1.createKoraSigner)(),
|
|
25
|
+
liveFirst: (0, env_1.isUniversalDeFiLiveFirstEnabled)(),
|
|
26
|
+
walletManager
|
|
27
|
+
});
|
|
28
|
+
const runner = new AgentRunner_1.AgentRunner();
|
|
29
|
+
const policyConfig = (0, policyPresets_1.resolvePolicyConfig)({
|
|
30
|
+
agentId: input.agent.name,
|
|
31
|
+
overrides: input.agent.policyOverrides,
|
|
32
|
+
presetName: input.agent.policyPreset
|
|
33
|
+
});
|
|
34
|
+
runner.registerAgent({
|
|
35
|
+
context: {
|
|
36
|
+
id: input.agent.name,
|
|
37
|
+
walletManager,
|
|
38
|
+
walletPublicKey: new web3_js_1.PublicKey(walletManager.publicKey.toBase58()),
|
|
39
|
+
rpcClient,
|
|
40
|
+
transactionService,
|
|
41
|
+
tokenService,
|
|
42
|
+
balanceService,
|
|
43
|
+
policyConfig: policyConfig,
|
|
44
|
+
logger: () => undefined,
|
|
45
|
+
universalDeFiExecutor: universalDeFi
|
|
46
|
+
},
|
|
47
|
+
strategy: (0, strategyFactory_1.createStrategy)({
|
|
48
|
+
name: input.overrideStrategy ?? input.agent.strategy,
|
|
49
|
+
config: input.agent.strategyConfig
|
|
50
|
+
}),
|
|
51
|
+
approvalMode: policyConfig.approvalMode
|
|
52
|
+
});
|
|
53
|
+
const [result] = await runner.runOnceParallel();
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getCliDataDir = getCliDataDir;
|
|
7
|
+
exports.resolveCliDataPath = resolveCliDataPath;
|
|
8
|
+
exports.getCliHomeEnvName = getCliHomeEnvName;
|
|
9
|
+
exports.probeCliDataDir = probeCliDataDir;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const os_1 = __importDefault(require("os"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const CLI_HOME_ENV = "PRKT_CLI_HOME";
|
|
14
|
+
function resolveBaseDir() {
|
|
15
|
+
const override = process.env[CLI_HOME_ENV]?.trim();
|
|
16
|
+
if (override) {
|
|
17
|
+
return path_1.default.resolve(override);
|
|
18
|
+
}
|
|
19
|
+
if (process.platform === "win32") {
|
|
20
|
+
const windowsBase = process.env.APPDATA || process.env.LOCALAPPDATA;
|
|
21
|
+
if (windowsBase) {
|
|
22
|
+
return path_1.default.join(windowsBase, "PRKT");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (process.platform === "darwin") {
|
|
26
|
+
return path_1.default.join(os_1.default.homedir(), "Library", "Application Support", "PRKT");
|
|
27
|
+
}
|
|
28
|
+
const xdgBase = process.env.XDG_DATA_HOME?.trim();
|
|
29
|
+
if (xdgBase) {
|
|
30
|
+
return path_1.default.join(xdgBase, "prkt");
|
|
31
|
+
}
|
|
32
|
+
return path_1.default.join(os_1.default.homedir(), ".local", "share", "prkt");
|
|
33
|
+
}
|
|
34
|
+
function getCliDataDir() {
|
|
35
|
+
const baseDir = resolveBaseDir();
|
|
36
|
+
(0, fs_1.mkdirSync)(baseDir, { recursive: true, mode: 0o700 });
|
|
37
|
+
return baseDir;
|
|
38
|
+
}
|
|
39
|
+
function resolveCliDataPath(fileName) {
|
|
40
|
+
return path_1.default.join(getCliDataDir(), fileName);
|
|
41
|
+
}
|
|
42
|
+
function getCliHomeEnvName() {
|
|
43
|
+
return CLI_HOME_ENV;
|
|
44
|
+
}
|
|
45
|
+
function probeCliDataDir() {
|
|
46
|
+
const dataDir = getCliDataDir();
|
|
47
|
+
const probePath = path_1.default.join(dataDir, ".prkt-write-test");
|
|
48
|
+
try {
|
|
49
|
+
(0, fs_1.writeFileSync)(probePath, "ok", { mode: 0o600 });
|
|
50
|
+
(0, fs_1.rmSync)(probePath, { force: true });
|
|
51
|
+
return {
|
|
52
|
+
details: "ok",
|
|
53
|
+
path: dataDir,
|
|
54
|
+
writable: true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
details: error instanceof Error ? error.message : "unknown write error",
|
|
60
|
+
path: dataDir,
|
|
61
|
+
writable: false
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStrategy = createStrategy;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const MemoHeartbeatStrategy_1 = require("../../agent/strategies/MemoHeartbeatStrategy");
|
|
6
|
+
const SimpleScriptedTransferStrategy_1 = require("../../agent/strategies/SimpleScriptedTransferStrategy");
|
|
7
|
+
const UniversalDeFiStrategy_1 = require("../../agent/strategies/UniversalDeFiStrategy");
|
|
8
|
+
function createStrategy(input) {
|
|
9
|
+
const name = input.name.trim().toLowerCase();
|
|
10
|
+
if (name === "memo-heartbeat") {
|
|
11
|
+
return new MemoHeartbeatStrategy_1.MemoHeartbeatStrategy();
|
|
12
|
+
}
|
|
13
|
+
if (name === "simple-scripted-transfer") {
|
|
14
|
+
const to = typeof input.config?.to === "string" ? input.config.to : undefined;
|
|
15
|
+
const amountSol = typeof input.config?.amountSol === "number" ? input.config.amountSol : 0.001;
|
|
16
|
+
if (!to) {
|
|
17
|
+
throw new Error("simple-scripted-transfer requires strategy config key 'to'.");
|
|
18
|
+
}
|
|
19
|
+
return new SimpleScriptedTransferStrategy_1.SimpleScriptedTransferStrategy({
|
|
20
|
+
to,
|
|
21
|
+
lamports: Math.round(amountSol * web3_js_1.LAMPORTS_PER_SOL),
|
|
22
|
+
memo: typeof input.config?.memo === "string"
|
|
23
|
+
? input.config.memo
|
|
24
|
+
: "cli simple-scripted-transfer"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (name === "universal-defi") {
|
|
28
|
+
return new UniversalDeFiStrategy_1.UniversalDeFiStrategy([
|
|
29
|
+
{
|
|
30
|
+
capability: "trade",
|
|
31
|
+
snapshot: {
|
|
32
|
+
buyThresholdUsd: 100,
|
|
33
|
+
solPriceUsd: 95
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
capability: "staking",
|
|
38
|
+
snapshot: {
|
|
39
|
+
idleSolLamports: Math.round(1 * web3_js_1.LAMPORTS_PER_SOL)
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
capability: "lp",
|
|
44
|
+
snapshot: {
|
|
45
|
+
liquidityInRange: true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
capability: "lending",
|
|
50
|
+
snapshot: {
|
|
51
|
+
healthFactor: 2.1,
|
|
52
|
+
idleUsdcAtomic: 5_000_000
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
capability: "borrowing",
|
|
57
|
+
snapshot: {
|
|
58
|
+
borrowDemandUsdcAtomic: 3_000_000,
|
|
59
|
+
collateralSolLamports: Math.round(1 * web3_js_1.LAMPORTS_PER_SOL),
|
|
60
|
+
healthFactor: 2.3
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`Unknown strategy '${input.name}'. Supported: memo-heartbeat, simple-scripted-transfer, universal-defi.`);
|
|
66
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.encryptSecretKeyForPlatform = encryptSecretKeyForPlatform;
|
|
7
|
+
exports.decryptSecretKeyForPlatform = decryptSecretKeyForPlatform;
|
|
8
|
+
exports.createRecoveryPackage = createRecoveryPackage;
|
|
9
|
+
exports.decryptSecretKeyWithRecovery = decryptSecretKeyWithRecovery;
|
|
10
|
+
exports.getPlatformMasterKeySource = getPlatformMasterKeySource;
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const storagePaths_1 = require("./storagePaths");
|
|
15
|
+
const MASTER_KEY_ENV = "PRKT_WALLET_MASTER_KEY";
|
|
16
|
+
const KEY_BYTES = 32;
|
|
17
|
+
function encryptSecretKeyForPlatform(secretKey) {
|
|
18
|
+
const { key } = resolvePlatformMasterKey({ allowCreate: true });
|
|
19
|
+
return encryptBytes(secretKey, key);
|
|
20
|
+
}
|
|
21
|
+
function decryptSecretKeyForPlatform(payload) {
|
|
22
|
+
const { key } = resolvePlatformMasterKey({ allowCreate: false });
|
|
23
|
+
return decryptBytes(payload, key);
|
|
24
|
+
}
|
|
25
|
+
function createRecoveryPackage(secretKey) {
|
|
26
|
+
const recoveryKey = encodeRecoveryKey((0, crypto_1.randomBytes)(KEY_BYTES));
|
|
27
|
+
const salt = (0, crypto_1.randomBytes)(16);
|
|
28
|
+
const key = (0, crypto_1.scryptSync)(recoveryKey, salt, KEY_BYTES);
|
|
29
|
+
const encrypted = encryptBytes(secretKey, key);
|
|
30
|
+
return {
|
|
31
|
+
recoveryKey,
|
|
32
|
+
recoveryPackage: {
|
|
33
|
+
algorithm: "scrypt-aes-256-gcm",
|
|
34
|
+
ciphertext: encrypted.ciphertext,
|
|
35
|
+
iv: encrypted.iv,
|
|
36
|
+
kdf: "scrypt",
|
|
37
|
+
salt: salt.toString("base64"),
|
|
38
|
+
tag: encrypted.tag
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function decryptSecretKeyWithRecovery(input) {
|
|
43
|
+
const key = (0, crypto_1.scryptSync)(input.recoveryKey, Buffer.from(input.recoveryPackage.salt, "base64"), KEY_BYTES);
|
|
44
|
+
return decryptBytes({
|
|
45
|
+
algorithm: "aes-256-gcm",
|
|
46
|
+
ciphertext: input.recoveryPackage.ciphertext,
|
|
47
|
+
iv: input.recoveryPackage.iv,
|
|
48
|
+
tag: input.recoveryPackage.tag
|
|
49
|
+
}, key);
|
|
50
|
+
}
|
|
51
|
+
function getPlatformMasterKeySource() {
|
|
52
|
+
return resolvePlatformMasterKey({ allowCreate: true }).source;
|
|
53
|
+
}
|
|
54
|
+
function resolvePlatformMasterKey(input) {
|
|
55
|
+
const masterKeyPath = (0, storagePaths_1.resolveCliDataPath)("platform-wallet-master.key");
|
|
56
|
+
const envValue = process.env[MASTER_KEY_ENV]?.trim();
|
|
57
|
+
if (envValue) {
|
|
58
|
+
return {
|
|
59
|
+
key: parseConfiguredKey(envValue),
|
|
60
|
+
source: "env"
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if ((0, fs_1.existsSync)(masterKeyPath)) {
|
|
64
|
+
return {
|
|
65
|
+
key: readStoredKey(masterKeyPath),
|
|
66
|
+
source: "local-file"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!input.allowCreate) {
|
|
70
|
+
throw new Error(`Wallet master key is not configured. Set ${MASTER_KEY_ENV} or create ${masterKeyPath}.`);
|
|
71
|
+
}
|
|
72
|
+
const generated = (0, crypto_1.randomBytes)(KEY_BYTES);
|
|
73
|
+
(0, fs_1.mkdirSync)(path_1.default.dirname(masterKeyPath), { recursive: true, mode: 0o700 });
|
|
74
|
+
(0, fs_1.writeFileSync)(masterKeyPath, generated.toString("base64"), { mode: 0o600 });
|
|
75
|
+
return {
|
|
76
|
+
key: generated,
|
|
77
|
+
source: "local-file"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function parseConfiguredKey(value) {
|
|
81
|
+
if (/^[0-9a-f]{64}$/iu.test(value)) {
|
|
82
|
+
return Buffer.from(value, "hex");
|
|
83
|
+
}
|
|
84
|
+
const base64 = Buffer.from(value, "base64");
|
|
85
|
+
if (base64.length === KEY_BYTES) {
|
|
86
|
+
return base64;
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`${MASTER_KEY_ENV} must be a 32-byte key encoded as base64 or 64 hex characters.`);
|
|
89
|
+
}
|
|
90
|
+
function readStoredKey(filePath) {
|
|
91
|
+
const raw = (0, fs_1.readFileSync)(filePath, "utf8").trim();
|
|
92
|
+
const parsed = Buffer.from(raw, "base64");
|
|
93
|
+
if (parsed.length !== KEY_BYTES) {
|
|
94
|
+
throw new Error(`Stored wallet master key at ${filePath} is invalid.`);
|
|
95
|
+
}
|
|
96
|
+
return parsed;
|
|
97
|
+
}
|
|
98
|
+
function encryptBytes(value, key) {
|
|
99
|
+
const iv = (0, crypto_1.randomBytes)(12);
|
|
100
|
+
const cipher = (0, crypto_1.createCipheriv)("aes-256-gcm", key, iv);
|
|
101
|
+
const ciphertext = Buffer.concat([cipher.update(Buffer.from(value)), cipher.final()]);
|
|
102
|
+
return {
|
|
103
|
+
algorithm: "aes-256-gcm",
|
|
104
|
+
ciphertext: ciphertext.toString("base64"),
|
|
105
|
+
iv: iv.toString("base64"),
|
|
106
|
+
tag: cipher.getAuthTag().toString("base64")
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function decryptBytes(payload, key) {
|
|
110
|
+
const decipher = (0, crypto_1.createDecipheriv)(payload.algorithm, key, Buffer.from(payload.iv, "base64"));
|
|
111
|
+
decipher.setAuthTag(Buffer.from(payload.tag, "base64"));
|
|
112
|
+
const plaintext = Buffer.concat([
|
|
113
|
+
decipher.update(Buffer.from(payload.ciphertext, "base64")),
|
|
114
|
+
decipher.final()
|
|
115
|
+
]);
|
|
116
|
+
return Uint8Array.from(plaintext);
|
|
117
|
+
}
|
|
118
|
+
function encodeRecoveryKey(bytes) {
|
|
119
|
+
return `prkt_recovery_${bytes.toString("base64url")}`;
|
|
120
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WalletRegistry = void 0;
|
|
7
|
+
exports.generateTemporaryWalletName = generateTemporaryWalletName;
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
11
|
+
const WalletManager_1 = require("../../core/wallet/WalletManager");
|
|
12
|
+
const walletCrypto_1 = require("./walletCrypto");
|
|
13
|
+
const storagePaths_1 = require("./storagePaths");
|
|
14
|
+
class WalletRegistry {
|
|
15
|
+
list() {
|
|
16
|
+
return this.read().wallets.slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
17
|
+
}
|
|
18
|
+
find(name) {
|
|
19
|
+
return this.read().wallets.find((wallet) => wallet.name === name);
|
|
20
|
+
}
|
|
21
|
+
create(name) {
|
|
22
|
+
const existing = this.find(name);
|
|
23
|
+
if (existing) {
|
|
24
|
+
throw new Error(`Wallet '${name}' already exists.`);
|
|
25
|
+
}
|
|
26
|
+
return this.provision({
|
|
27
|
+
name,
|
|
28
|
+
secretKey: web3_js_1.Keypair.generate().secretKey
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
toWalletManager(name) {
|
|
32
|
+
const record = this.requireRecord(name);
|
|
33
|
+
return WalletManager_1.WalletManager.fromSecretKey(this.resolveSecretKey(record), "generated");
|
|
34
|
+
}
|
|
35
|
+
ensureFromEnv(name) {
|
|
36
|
+
const existing = this.find(name);
|
|
37
|
+
if (existing) {
|
|
38
|
+
return {
|
|
39
|
+
created: false,
|
|
40
|
+
record: existing,
|
|
41
|
+
recoveryKey: null
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const fromEnv = WalletManager_1.WalletManager.loadFromEnv();
|
|
45
|
+
return this.provision({
|
|
46
|
+
name,
|
|
47
|
+
secretKey: fromEnv.payer.secretKey
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
exportSecretKeyWithRecovery(input) {
|
|
51
|
+
const record = this.requireRecord(input.name);
|
|
52
|
+
if (!record.recoveryPackage) {
|
|
53
|
+
throw new Error(`Wallet '${input.name}' does not have a recovery package.`);
|
|
54
|
+
}
|
|
55
|
+
return (0, walletCrypto_1.decryptSecretKeyWithRecovery)({
|
|
56
|
+
recoveryKey: input.recoveryKey,
|
|
57
|
+
recoveryPackage: record.recoveryPackage
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
provision(input) {
|
|
61
|
+
const wallet = WalletManager_1.WalletManager.fromSecretKey(input.secretKey, "generated");
|
|
62
|
+
const recovery = (0, walletCrypto_1.createRecoveryPackage)(input.secretKey);
|
|
63
|
+
const record = {
|
|
64
|
+
createdAtIso: new Date().toISOString(),
|
|
65
|
+
encryptedSecretKey: (0, walletCrypto_1.encryptSecretKeyForPlatform)(input.secretKey),
|
|
66
|
+
name: input.name,
|
|
67
|
+
publicKey: wallet.publicKey.toBase58(),
|
|
68
|
+
recoveryPackage: recovery.recoveryPackage,
|
|
69
|
+
version: 2
|
|
70
|
+
};
|
|
71
|
+
const registry = this.read();
|
|
72
|
+
registry.wallets.push(record);
|
|
73
|
+
this.write(registry);
|
|
74
|
+
return {
|
|
75
|
+
created: true,
|
|
76
|
+
record,
|
|
77
|
+
recoveryKey: recovery.recoveryKey
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
requireRecord(name) {
|
|
81
|
+
const registry = this.read();
|
|
82
|
+
const record = registry.wallets.find((wallet) => wallet.name === name);
|
|
83
|
+
if (!record) {
|
|
84
|
+
throw new Error(`Wallet '${name}' not found.`);
|
|
85
|
+
}
|
|
86
|
+
const migrated = this.maybeMigrateLegacyRecord(registry, record);
|
|
87
|
+
return migrated ?? record;
|
|
88
|
+
}
|
|
89
|
+
read() {
|
|
90
|
+
const registryPath = (0, storagePaths_1.resolveCliDataPath)("cli-wallets.json");
|
|
91
|
+
if (!(0, fs_1.existsSync)(registryPath)) {
|
|
92
|
+
return {
|
|
93
|
+
wallets: []
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const raw = (0, fs_1.readFileSync)(registryPath, "utf8");
|
|
97
|
+
const parsed = JSON.parse(raw);
|
|
98
|
+
return {
|
|
99
|
+
wallets: (parsed.wallets ?? []).map((wallet) => this.normalize(wallet))
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
write(payload) {
|
|
103
|
+
const registryPath = (0, storagePaths_1.resolveCliDataPath)("cli-wallets.json");
|
|
104
|
+
(0, fs_1.mkdirSync)(path_1.default.dirname(registryPath), { recursive: true, mode: 0o700 });
|
|
105
|
+
(0, fs_1.writeFileSync)(registryPath, JSON.stringify(payload, null, 2), { mode: 0o600 });
|
|
106
|
+
}
|
|
107
|
+
maybeMigrateLegacyRecord(registry, record) {
|
|
108
|
+
if (!record.secretKey || record.encryptedSecretKey) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const secretKey = Uint8Array.from(record.secretKey);
|
|
112
|
+
const recovery = (0, walletCrypto_1.createRecoveryPackage)(secretKey);
|
|
113
|
+
const migrated = {
|
|
114
|
+
createdAtIso: record.createdAtIso,
|
|
115
|
+
encryptedSecretKey: (0, walletCrypto_1.encryptSecretKeyForPlatform)(secretKey),
|
|
116
|
+
name: record.name,
|
|
117
|
+
publicKey: record.publicKey,
|
|
118
|
+
recoveryPackage: recovery.recoveryPackage,
|
|
119
|
+
version: 2
|
|
120
|
+
};
|
|
121
|
+
const index = registry.wallets.findIndex((entry) => entry.name === record.name);
|
|
122
|
+
registry.wallets[index] = migrated;
|
|
123
|
+
this.write(registry);
|
|
124
|
+
return migrated;
|
|
125
|
+
}
|
|
126
|
+
normalize(wallet) {
|
|
127
|
+
return {
|
|
128
|
+
...wallet,
|
|
129
|
+
version: wallet.version ?? (wallet.encryptedSecretKey ? 2 : 1)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
resolveSecretKey(record) {
|
|
133
|
+
if (record.encryptedSecretKey) {
|
|
134
|
+
return (0, walletCrypto_1.decryptSecretKeyForPlatform)(record.encryptedSecretKey);
|
|
135
|
+
}
|
|
136
|
+
if (record.secretKey) {
|
|
137
|
+
return Uint8Array.from(record.secretKey);
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Wallet '${record.name}' does not contain recoverable key material.`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.WalletRegistry = WalletRegistry;
|
|
143
|
+
function generateTemporaryWalletName() {
|
|
144
|
+
return `wallet-${web3_js_1.Keypair.generate().publicKey.toBase58().slice(0, 8)}`;
|
|
145
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.completionWords = completionWords;
|
|
4
|
+
exports.buildBashCompletion = buildBashCompletion;
|
|
5
|
+
exports.buildZshCompletion = buildZshCompletion;
|
|
6
|
+
exports.buildPowerShellCompletion = buildPowerShellCompletion;
|
|
7
|
+
const TOP_LEVEL_COMMANDS = [
|
|
8
|
+
"wallet",
|
|
9
|
+
"token",
|
|
10
|
+
"policy",
|
|
11
|
+
"agent",
|
|
12
|
+
"monitor",
|
|
13
|
+
"demo",
|
|
14
|
+
"audit",
|
|
15
|
+
"config",
|
|
16
|
+
"doctor",
|
|
17
|
+
"completion"
|
|
18
|
+
];
|
|
19
|
+
function completionWords() {
|
|
20
|
+
return TOP_LEVEL_COMMANDS.join(" ");
|
|
21
|
+
}
|
|
22
|
+
function buildBashCompletion() {
|
|
23
|
+
return `# bash completion for prkt
|
|
24
|
+
_prkt_completion() {
|
|
25
|
+
local cur cword
|
|
26
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
27
|
+
cword=$COMP_CWORD
|
|
28
|
+
local commands="${completionWords()}"
|
|
29
|
+
if [[ $cword -eq 1 ]]; then
|
|
30
|
+
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
|
31
|
+
return
|
|
32
|
+
fi
|
|
33
|
+
}
|
|
34
|
+
complete -F _prkt_completion prkt
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
function buildZshCompletion() {
|
|
38
|
+
return `#compdef prkt
|
|
39
|
+
_prkt() {
|
|
40
|
+
local -a commands
|
|
41
|
+
commands=(${completionWords()})
|
|
42
|
+
if (( CURRENT == 2 )); then
|
|
43
|
+
_describe 'command' commands
|
|
44
|
+
return
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
compdef _prkt prkt
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
function buildPowerShellCompletion() {
|
|
51
|
+
return `Register-ArgumentCompleter -Native -CommandName prkt -ScriptBlock {
|
|
52
|
+
param($wordToComplete, $commandAst, $cursorPosition)
|
|
53
|
+
$commands = @(${completionWords()
|
|
54
|
+
.split(" ")
|
|
55
|
+
.map((word) => `'${word}'`)
|
|
56
|
+
.join(", ")})
|
|
57
|
+
$commands | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {
|
|
58
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
}
|