@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,164 @@
|
|
|
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.getEmergencyLockStatus = getEmergencyLockStatus;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const EMERGENCY_FLAG_ENV = "POLICY_EMERGENCY_LOCK";
|
|
11
|
+
const EMERGENCY_LOCK_PATH_ENV = "POLICY_EMERGENCY_LOCK_PATH";
|
|
12
|
+
const EMERGENCY_COMMAND_PATH_ENV = "POLICY_EMERGENCY_COMMAND_PATH";
|
|
13
|
+
const EMERGENCY_COMMAND_SECRET_ENV = "POLICY_EMERGENCY_ADMIN_SECRET";
|
|
14
|
+
const EMERGENCY_COMMAND_MAX_AGE_SECONDS_ENV = "POLICY_EMERGENCY_MAX_AGE_SECONDS";
|
|
15
|
+
const DEFAULT_EMERGENCY_LOCK_PATH = path_1.default.join(process.cwd(), "emergency_lock.json");
|
|
16
|
+
const DEFAULT_EMERGENCY_COMMAND_PATH = path_1.default.join(process.cwd(), "emergency_command.json");
|
|
17
|
+
function getEmergencyLockStatus() {
|
|
18
|
+
const flag = process.env[EMERGENCY_FLAG_ENV]?.trim().toLowerCase();
|
|
19
|
+
if (flag === "true" || flag === "1") {
|
|
20
|
+
return {
|
|
21
|
+
locked: true,
|
|
22
|
+
reason: `Human-in-the-loop Override engaged via ${EMERGENCY_FLAG_ENV}.`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const signedCommandStatus = getSignedEmergencyCommandStatus();
|
|
26
|
+
if (signedCommandStatus.locked) {
|
|
27
|
+
return signedCommandStatus;
|
|
28
|
+
}
|
|
29
|
+
const emergencyLockPath = getEmergencyLockPath();
|
|
30
|
+
if (!(0, fs_1.existsSync)(emergencyLockPath)) {
|
|
31
|
+
return {
|
|
32
|
+
locked: false,
|
|
33
|
+
reason: null
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const raw = (0, fs_1.readFileSync)(emergencyLockPath, "utf8").trim();
|
|
38
|
+
if (raw.length === 0) {
|
|
39
|
+
return {
|
|
40
|
+
locked: true,
|
|
41
|
+
reason: `Human-in-the-loop Override engaged via ${path_1.default.basename(emergencyLockPath)}.`
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const parsed = JSON.parse(raw);
|
|
45
|
+
const enabled = parsed.enabled ?? parsed.locked ?? false;
|
|
46
|
+
if (enabled) {
|
|
47
|
+
return {
|
|
48
|
+
locked: true,
|
|
49
|
+
reason: parsed.reason?.trim() ||
|
|
50
|
+
`Human-in-the-loop Override engaged via ${path_1.default.basename(emergencyLockPath)}.`
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
locked: false,
|
|
55
|
+
reason: null
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return {
|
|
60
|
+
locked: true,
|
|
61
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(emergencyLockPath)} is invalid.`
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function getEmergencyLockPath() {
|
|
66
|
+
const override = process.env[EMERGENCY_LOCK_PATH_ENV]?.trim();
|
|
67
|
+
if (!override) {
|
|
68
|
+
return DEFAULT_EMERGENCY_LOCK_PATH;
|
|
69
|
+
}
|
|
70
|
+
return path_1.default.isAbsolute(override) ? override : path_1.default.join(process.cwd(), override);
|
|
71
|
+
}
|
|
72
|
+
function getEmergencyCommandPath() {
|
|
73
|
+
const override = process.env[EMERGENCY_COMMAND_PATH_ENV]?.trim();
|
|
74
|
+
if (!override) {
|
|
75
|
+
return DEFAULT_EMERGENCY_COMMAND_PATH;
|
|
76
|
+
}
|
|
77
|
+
return path_1.default.isAbsolute(override) ? override : path_1.default.join(process.cwd(), override);
|
|
78
|
+
}
|
|
79
|
+
function getEmergencyCommandMaxAgeMs() {
|
|
80
|
+
const raw = process.env[EMERGENCY_COMMAND_MAX_AGE_SECONDS_ENV]?.trim();
|
|
81
|
+
if (!raw) {
|
|
82
|
+
return 10 * 60 * 1000;
|
|
83
|
+
}
|
|
84
|
+
const parsed = Number(raw);
|
|
85
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
86
|
+
return 10 * 60 * 1000;
|
|
87
|
+
}
|
|
88
|
+
return parsed * 1000;
|
|
89
|
+
}
|
|
90
|
+
function getSignedEmergencyCommandStatus() {
|
|
91
|
+
const commandPath = getEmergencyCommandPath();
|
|
92
|
+
if (!(0, fs_1.existsSync)(commandPath)) {
|
|
93
|
+
return {
|
|
94
|
+
locked: false,
|
|
95
|
+
reason: null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const secret = process.env[EMERGENCY_COMMAND_SECRET_ENV]?.trim();
|
|
99
|
+
if (!secret) {
|
|
100
|
+
return {
|
|
101
|
+
locked: true,
|
|
102
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(commandPath)} exists but ${EMERGENCY_COMMAND_SECRET_ENV} is not configured.`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const raw = (0, fs_1.readFileSync)(commandPath, "utf8").trim();
|
|
107
|
+
if (!raw) {
|
|
108
|
+
return {
|
|
109
|
+
locked: true,
|
|
110
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(commandPath)} is empty.`
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const command = JSON.parse(raw);
|
|
114
|
+
const payload = `${command.enabled}:${command.issuedAtIso8601}:${command.reason ?? ""}`;
|
|
115
|
+
if (!verifySignature(payload, command.signature, secret)) {
|
|
116
|
+
return {
|
|
117
|
+
locked: true,
|
|
118
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(commandPath)} signature verification failed.`
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const issuedAt = Date.parse(command.issuedAtIso8601);
|
|
122
|
+
if (Number.isNaN(issuedAt)) {
|
|
123
|
+
return {
|
|
124
|
+
locked: true,
|
|
125
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(commandPath)} timestamp is invalid.`
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (Date.now() - issuedAt > getEmergencyCommandMaxAgeMs()) {
|
|
129
|
+
return {
|
|
130
|
+
locked: true,
|
|
131
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(commandPath)} is stale.`
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (command.enabled) {
|
|
135
|
+
return {
|
|
136
|
+
locked: true,
|
|
137
|
+
reason: command.reason?.trim() ||
|
|
138
|
+
`Human-in-the-loop Override engaged via signed ${path_1.default.basename(commandPath)}.`
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
locked: false,
|
|
143
|
+
reason: null
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return {
|
|
148
|
+
locked: true,
|
|
149
|
+
reason: `Human-in-the-loop Override engaged because ${path_1.default.basename(commandPath)} is invalid.`
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function verifySignature(payload, signature, secret) {
|
|
154
|
+
if (!signature || !secret) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
const expected = (0, crypto_1.createHmac)("sha256", secret).update(payload).digest("hex");
|
|
158
|
+
const expectedBytes = Buffer.from(expected, "utf8");
|
|
159
|
+
const providedBytes = Buffer.from(signature, "utf8");
|
|
160
|
+
if (expectedBytes.length !== providedBytes.length) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return (0, crypto_1.timingSafeEqual)(expectedBytes, providedBytes);
|
|
164
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PolicyEngine = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const emergencyLock_1 = require("../emergencyLock");
|
|
7
|
+
const programs_1 = require("../../solana/programs");
|
|
8
|
+
class PolicyEngine {
|
|
9
|
+
policyConfig;
|
|
10
|
+
sessionStart = Date.now();
|
|
11
|
+
txCountSession = 0;
|
|
12
|
+
perDayCounts = new Map();
|
|
13
|
+
auditLog = [];
|
|
14
|
+
constructor(policyConfig) {
|
|
15
|
+
this.policyConfig = policyConfig;
|
|
16
|
+
}
|
|
17
|
+
inspect(transaction, context) {
|
|
18
|
+
const reasons = [];
|
|
19
|
+
const decompiledMessage = web3_js_1.TransactionMessage.decompile(transaction.message);
|
|
20
|
+
let totalSolSpendLamports = 0n;
|
|
21
|
+
let totalSplSpendRaw = 0n;
|
|
22
|
+
const programsSeen = new Set();
|
|
23
|
+
const mintsSeen = new Set();
|
|
24
|
+
let hasUncheckedSplSpend = false;
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
const emergencyStatus = (0, emergencyLock_1.getEmergencyLockStatus)();
|
|
27
|
+
if (emergencyStatus.locked) {
|
|
28
|
+
reasons.push(emergencyStatus.reason ?? "Human-in-the-loop Override engaged.");
|
|
29
|
+
}
|
|
30
|
+
const sessionExpiry = Date.parse(this.policyConfig.sessionExpiresAtIso8601);
|
|
31
|
+
if (Number.isNaN(sessionExpiry) || now > sessionExpiry) {
|
|
32
|
+
reasons.push("session expired");
|
|
33
|
+
}
|
|
34
|
+
const dayKey = new Date(now).toISOString().slice(0, 10);
|
|
35
|
+
const todaysCount = this.perDayCounts.get(dayKey) ?? 0;
|
|
36
|
+
if (this.txCountSession >= this.policyConfig.limits.maxTransactionsPerSession) {
|
|
37
|
+
reasons.push("max transactions per session exceeded");
|
|
38
|
+
}
|
|
39
|
+
if (todaysCount >= this.policyConfig.limits.maxTransactionsPerDay) {
|
|
40
|
+
reasons.push("max transactions per day exceeded");
|
|
41
|
+
}
|
|
42
|
+
for (const instruction of decompiledMessage.instructions) {
|
|
43
|
+
const programId = instruction.programId.toBase58();
|
|
44
|
+
programsSeen.add(programId);
|
|
45
|
+
if (!this.policyConfig.rules.allowedProgramIds.includes(programId)) {
|
|
46
|
+
reasons.push(`program not allowed: ${programId}`);
|
|
47
|
+
if (this.policyConfig.rules.denyUnknownInstructionsByDefault) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const blockedVectorReason = this.detectBlockedSpendVector(instruction);
|
|
52
|
+
if (blockedVectorReason) {
|
|
53
|
+
reasons.push(blockedVectorReason);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const spend = this.tryDecodeSpend(instruction);
|
|
57
|
+
if (!spend) {
|
|
58
|
+
if (this.policyConfig.rules.denyUnknownInstructionsByDefault &&
|
|
59
|
+
!this.policyConfig.rules.allowOpaqueProgramIds?.includes(programId) &&
|
|
60
|
+
!this.isKnownNonSpendInstruction(programId)) {
|
|
61
|
+
reasons.push(`opaque instruction blocked: ${programId}`);
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (spend.kind === "sol") {
|
|
66
|
+
totalSolSpendLamports += spend.amount;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
totalSplSpendRaw += spend.amount;
|
|
70
|
+
hasUncheckedSplSpend ||= !spend.mintVerified;
|
|
71
|
+
if (spend.mint) {
|
|
72
|
+
mintsSeen.add(spend.mint.toBase58());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (this.policyConfig.rules.allowedTransferDestinations &&
|
|
76
|
+
this.policyConfig.rules.allowedTransferDestinations.length > 0) {
|
|
77
|
+
const destination = spend.destination.toBase58();
|
|
78
|
+
if (!this.policyConfig.rules.allowedTransferDestinations.includes(destination)) {
|
|
79
|
+
reasons.push(`destination not allowlisted: ${destination}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (totalSolSpendLamports > BigInt(this.policyConfig.limits.maxSolPerTxLamports)) {
|
|
84
|
+
reasons.push("max SOL per transaction exceeded");
|
|
85
|
+
}
|
|
86
|
+
if (totalSplSpendRaw > this.policyConfig.limits.maxSplPerTxRawAmount) {
|
|
87
|
+
reasons.push("max SPL per transaction exceeded");
|
|
88
|
+
}
|
|
89
|
+
if (this.policyConfig.rules.allowedMintAddresses.length > 0) {
|
|
90
|
+
if (hasUncheckedSplSpend) {
|
|
91
|
+
reasons.push("unchecked SPL transfer cannot be validated against mint allowlist");
|
|
92
|
+
}
|
|
93
|
+
for (const seenMint of mintsSeen) {
|
|
94
|
+
if (!this.policyConfig.rules.allowedMintAddresses.includes(seenMint)) {
|
|
95
|
+
reasons.push(`mint not allowed: ${seenMint}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (this.policyConfig.rules.rejectSuspiciousBalanceDeltas &&
|
|
100
|
+
context?.expectedBalanceDeltas &&
|
|
101
|
+
context.expectedBalanceDeltas.some((delta) => delta.maxNegativeDeltaRaw < 0n)) {
|
|
102
|
+
reasons.push("invalid expected balance delta");
|
|
103
|
+
}
|
|
104
|
+
const allowed = reasons.length === 0;
|
|
105
|
+
const result = {
|
|
106
|
+
allowed,
|
|
107
|
+
reasons,
|
|
108
|
+
details: {
|
|
109
|
+
totalSolSpendLamports,
|
|
110
|
+
totalSplSpendRaw,
|
|
111
|
+
programsSeen: Array.from(programsSeen),
|
|
112
|
+
mintsSeen: Array.from(mintsSeen)
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
this.auditLog.push({
|
|
116
|
+
agentId: this.policyConfig.agentId,
|
|
117
|
+
timestampIso8601: new Date().toISOString(),
|
|
118
|
+
decision: allowed ? "allow" : "deny",
|
|
119
|
+
reason: allowed ? "policy checks passed" : reasons.join("; ")
|
|
120
|
+
});
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
recordBroadcast(signature) {
|
|
124
|
+
this.txCountSession += 1;
|
|
125
|
+
const dayKey = new Date().toISOString().slice(0, 10);
|
|
126
|
+
this.perDayCounts.set(dayKey, (this.perDayCounts.get(dayKey) ?? 0) + 1);
|
|
127
|
+
this.auditLog.push({
|
|
128
|
+
agentId: this.policyConfig.agentId,
|
|
129
|
+
timestampIso8601: new Date().toISOString(),
|
|
130
|
+
decision: "allow",
|
|
131
|
+
reason: "broadcasted",
|
|
132
|
+
txSignature: signature
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
getAuditTrail() {
|
|
136
|
+
return [...this.auditLog];
|
|
137
|
+
}
|
|
138
|
+
getSessionAgeMs() {
|
|
139
|
+
return Date.now() - this.sessionStart;
|
|
140
|
+
}
|
|
141
|
+
tryDecodeSpend(instruction) {
|
|
142
|
+
if (instruction.programId.equals(web3_js_1.SystemProgram.programId)) {
|
|
143
|
+
try {
|
|
144
|
+
const transfer = web3_js_1.SystemInstruction.decodeTransfer(instruction);
|
|
145
|
+
return {
|
|
146
|
+
kind: "sol",
|
|
147
|
+
amount: transfer.lamports,
|
|
148
|
+
destination: transfer.toPubkey
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const transfer = (0, spl_token_1.decodeTransferInstruction)(instruction);
|
|
157
|
+
return {
|
|
158
|
+
kind: "spl",
|
|
159
|
+
amount: BigInt(transfer.data.amount.toString()),
|
|
160
|
+
destination: transfer.keys.destination.pubkey,
|
|
161
|
+
mint: null,
|
|
162
|
+
mintVerified: false
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// ignore
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const transfer = (0, spl_token_1.decodeTransferCheckedInstruction)(instruction);
|
|
170
|
+
return {
|
|
171
|
+
kind: "spl",
|
|
172
|
+
amount: BigInt(transfer.data.amount.toString()),
|
|
173
|
+
destination: transfer.keys.destination.pubkey,
|
|
174
|
+
mint: transfer.keys.mint.pubkey,
|
|
175
|
+
mintVerified: true
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// ignore
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
detectBlockedSpendVector(instruction) {
|
|
184
|
+
try {
|
|
185
|
+
const approve = (0, spl_token_1.decodeApproveInstruction)(instruction);
|
|
186
|
+
return `delegate approval blocked: ${approve.keys.delegate.pubkey.toBase58()}`;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// ignore
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const approveChecked = (0, spl_token_1.decodeApproveCheckedInstruction)(instruction);
|
|
193
|
+
return `delegate approval blocked: ${approveChecked.keys.delegate.pubkey.toBase58()}`;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// ignore
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const revoke = (0, spl_token_1.decodeRevokeInstruction)(instruction);
|
|
200
|
+
return `delegate revoke requires explicit approval: ${revoke.keys.account.pubkey.toBase58()}`;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// ignore
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const closeAccount = (0, spl_token_1.decodeCloseAccountInstruction)(instruction);
|
|
207
|
+
const destination = closeAccount.keys.destination.pubkey.toBase58();
|
|
208
|
+
if (this.policyConfig.rules.allowedCloseAccountDestinations?.includes(destination) ?? false) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
return `close-account drain blocked: ${closeAccount.keys.destination.pubkey.toBase58()}`;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// ignore
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const setAuthority = (0, spl_token_1.decodeSetAuthorityInstruction)(instruction);
|
|
218
|
+
if (setAuthority.data.authorityType === spl_token_1.AuthorityType.AccountOwner ||
|
|
219
|
+
setAuthority.data.authorityType === spl_token_1.AuthorityType.CloseAccount ||
|
|
220
|
+
setAuthority.data.authorityType === spl_token_1.AuthorityType.MintTokens) {
|
|
221
|
+
return `authority change blocked: ${spl_token_1.AuthorityType[setAuthority.data.authorityType]}`;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// ignore
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
isKnownNonSpendInstruction(programId) {
|
|
230
|
+
return (programId === web3_js_1.SystemProgram.programId.toBase58() ||
|
|
231
|
+
programId === programs_1.TOKEN_PROGRAM_ID.toBase58() ||
|
|
232
|
+
programId === programs_1.ASSOCIATED_TOKEN_PROGRAM_ID.toBase58() ||
|
|
233
|
+
programId === programs_1.MEMO_PROGRAM_ID.toBase58() ||
|
|
234
|
+
(this.policyConfig.rules.allowOpaqueProgramIds?.includes(programId) ?? false));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
exports.PolicyEngine = PolicyEngine;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecurityViolationError = void 0;
|
|
4
|
+
class SecurityViolationError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "SecurityViolationError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.SecurityViolationError = SecurityViolationError;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxExecutor = exports.PolicyEngine = void 0;
|
|
4
|
+
var PolicyEngine_1 = require("./engine/PolicyEngine");
|
|
5
|
+
Object.defineProperty(exports, "PolicyEngine", { enumerable: true, get: function () { return PolicyEngine_1.PolicyEngine; } });
|
|
6
|
+
var SandboxExecutor_1 = require("./sandbox/SandboxExecutor");
|
|
7
|
+
Object.defineProperty(exports, "SandboxExecutor", { enumerable: true, get: function () { return SandboxExecutor_1.SandboxExecutor; } });
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxExecutor = void 0;
|
|
4
|
+
class SandboxExecutor {
|
|
5
|
+
policyEngine;
|
|
6
|
+
transactionService;
|
|
7
|
+
approvalMode;
|
|
8
|
+
approvalCallback;
|
|
9
|
+
constructor(policyEngine, transactionService, approvalMode, approvalCallback) {
|
|
10
|
+
this.policyEngine = policyEngine;
|
|
11
|
+
this.transactionService = transactionService;
|
|
12
|
+
this.approvalMode = approvalMode;
|
|
13
|
+
this.approvalCallback = approvalCallback;
|
|
14
|
+
}
|
|
15
|
+
async executePreparedTransaction(input) {
|
|
16
|
+
const inspection = this.policyEngine.inspect(input.transaction, input.inspectionContext);
|
|
17
|
+
if (!inspection.allowed) {
|
|
18
|
+
return {
|
|
19
|
+
inspection,
|
|
20
|
+
signature: null,
|
|
21
|
+
simulationLogs: null
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const simulation = await this.transactionService.simulate(input.transaction);
|
|
25
|
+
if (simulation.err) {
|
|
26
|
+
return {
|
|
27
|
+
inspection: {
|
|
28
|
+
...inspection,
|
|
29
|
+
allowed: false,
|
|
30
|
+
reasons: [...inspection.reasons, "simulation failed"]
|
|
31
|
+
},
|
|
32
|
+
signature: null,
|
|
33
|
+
simulationLogs: simulation.logs
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (this.approvalMode === "live") {
|
|
37
|
+
if (!this.approvalCallback) {
|
|
38
|
+
return {
|
|
39
|
+
inspection: {
|
|
40
|
+
...inspection,
|
|
41
|
+
allowed: false,
|
|
42
|
+
reasons: [...inspection.reasons, "live approval callback missing"]
|
|
43
|
+
},
|
|
44
|
+
signature: null,
|
|
45
|
+
simulationLogs: simulation.logs
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const approved = await this.approvalCallback({
|
|
49
|
+
agentId: this.policyEngine.getAuditTrail().at(-1)?.agentId ?? "unknown-agent",
|
|
50
|
+
inspection,
|
|
51
|
+
transaction: input.transaction
|
|
52
|
+
});
|
|
53
|
+
if (!approved) {
|
|
54
|
+
return {
|
|
55
|
+
inspection: {
|
|
56
|
+
...inspection,
|
|
57
|
+
allowed: false,
|
|
58
|
+
reasons: [...inspection.reasons, "manual approval rejected"]
|
|
59
|
+
},
|
|
60
|
+
signature: null,
|
|
61
|
+
simulationLogs: simulation.logs
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const send = await this.transactionService.sendAndConfirm({
|
|
66
|
+
confirmationStrategy: input.confirmationStrategy,
|
|
67
|
+
transaction: input.transaction
|
|
68
|
+
});
|
|
69
|
+
this.policyEngine.recordBroadcast(send.signature);
|
|
70
|
+
return {
|
|
71
|
+
inspection,
|
|
72
|
+
signature: send.signature,
|
|
73
|
+
simulationLogs: simulation.logs
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.SandboxExecutor = SandboxExecutor;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureWalletHasMinimumSol = ensureWalletHasMinimumSol;
|
|
4
|
+
const SOL_BALANCE_TOLERANCE = 0.000001;
|
|
5
|
+
async function ensureWalletHasMinimumSol(input) {
|
|
6
|
+
const funding = await input.fundingService.ensureMinimumSol({
|
|
7
|
+
airdropAmountSol: 1,
|
|
8
|
+
balanceService: input.balanceService,
|
|
9
|
+
minimumSol: input.minimumSol,
|
|
10
|
+
recipient: input.publicKey
|
|
11
|
+
});
|
|
12
|
+
if (!funding) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const updatedBalance = await input.fundingService.waitForMinimumBalance({
|
|
16
|
+
balanceService: input.balanceService,
|
|
17
|
+
minimumSol: input.minimumSol,
|
|
18
|
+
recipient: input.publicKey
|
|
19
|
+
});
|
|
20
|
+
if (updatedBalance + SOL_BALANCE_TOLERANCE >= input.minimumSol) {
|
|
21
|
+
console.log(`Funding source: ${funding.source}`);
|
|
22
|
+
console.log(`Funding signature: ${funding.signature}`);
|
|
23
|
+
console.log(`SOL after funding: ${updatedBalance.toFixed(4)}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const finalBalance = await input.balanceService.getSolBalance(input.publicKey);
|
|
27
|
+
throw new Error(`Funding failed: wallet balance is ${finalBalance.toFixed(4)} SOL after ${funding.source}, below required ${input.minimumSol.toFixed(4)} SOL.`);
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_STARTING_WSOL_FOR_WRAP_DEMO = exports.REQUIRED_STARTING_SOL = void 0;
|
|
4
|
+
exports.assertDeterministicWrapPreflight = assertDeterministicWrapPreflight;
|
|
5
|
+
exports.REQUIRED_STARTING_SOL = 0.12;
|
|
6
|
+
exports.MAX_STARTING_WSOL_FOR_WRAP_DEMO = 0.0099;
|
|
7
|
+
function assertDeterministicWrapPreflight(input) {
|
|
8
|
+
const requiredStartingSol = input.requiredStartingSol ?? exports.REQUIRED_STARTING_SOL;
|
|
9
|
+
const maxStartingWsol = input.maxStartingWsol ?? exports.MAX_STARTING_WSOL_FOR_WRAP_DEMO;
|
|
10
|
+
if (input.startingSolBalance < requiredStartingSol) {
|
|
11
|
+
throw new Error(`Preflight failed: wallet has ${input.startingSolBalance.toFixed(4)} SOL. Fund at least ${requiredStartingSol.toFixed(2)} SOL on devnet before running wallet:devnet.`);
|
|
12
|
+
}
|
|
13
|
+
if (input.startingWsolBalance > maxStartingWsol) {
|
|
14
|
+
throw new Error(`Preflight failed: wallet already has ${input.startingWsolBalance.toFixed(4)} wSOL. For a deterministic wrap demo, reduce wSOL below ${maxStartingWsol.toFixed(4)} and rerun.`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
4
|
+
const env_1 = require("../config/env");
|
|
5
|
+
const WalletManager_1 = require("../wallet/WalletManager");
|
|
6
|
+
async function main() {
|
|
7
|
+
try {
|
|
8
|
+
const rpcUrl = (0, env_1.getRpcUrl)();
|
|
9
|
+
console.log(`RPC URL: ${rpcUrl}`);
|
|
10
|
+
const walletManager = WalletManager_1.WalletManager.loadConfigured();
|
|
11
|
+
console.log(`Wallet pubkey: ${walletManager.publicKey.toBase58()}`);
|
|
12
|
+
console.log(`Wallet source: ${walletManager.source}`);
|
|
13
|
+
const connection = new web3_js_1.Connection(rpcUrl, "confirmed");
|
|
14
|
+
const balance = await connection.getBalance(walletManager.publicKey);
|
|
15
|
+
console.log(`Balance: ${balance / 1_000_000_000} SOL (${balance} lamports)`);
|
|
16
|
+
console.log("Localnet connectivity check PASSED.");
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20
|
+
console.error(`Localnet check FAILED: ${message}`);
|
|
21
|
+
if (error instanceof Error && error.stack) {
|
|
22
|
+
console.error(error.stack);
|
|
23
|
+
}
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
main();
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getManagedAgentName = getManagedAgentName;
|
|
4
|
+
exports.getManagedOwnerId = getManagedOwnerId;
|
|
5
|
+
exports.resolveManagedAgentWallet = resolveManagedAgentWallet;
|
|
6
|
+
exports.ensureManagedAgentWalletFunding = ensureManagedAgentWalletFunding;
|
|
7
|
+
exports.logManagedAgentWallet = logManagedAgentWallet;
|
|
8
|
+
const agentRegistry_1 = require("../cli/services/agentRegistry");
|
|
9
|
+
const walletRegistry_1 = require("../cli/services/walletRegistry");
|
|
10
|
+
const devnetFunding_1 = require("./devnetFunding");
|
|
11
|
+
const AGENT_NAME_ENV = "PRKT_AGENT_NAME";
|
|
12
|
+
const OWNER_ID_ENV = "PRKT_OWNER_ID";
|
|
13
|
+
function getManagedAgentName(input) {
|
|
14
|
+
const configuredName = input.env?.[AGENT_NAME_ENV]?.trim();
|
|
15
|
+
if (configuredName) {
|
|
16
|
+
return configuredName;
|
|
17
|
+
}
|
|
18
|
+
return input.defaultAgentName;
|
|
19
|
+
}
|
|
20
|
+
function getManagedOwnerId(env) {
|
|
21
|
+
const configuredOwnerId = env?.[OWNER_ID_ENV]?.trim();
|
|
22
|
+
return configuredOwnerId && configuredOwnerId.length > 0 ? configuredOwnerId : undefined;
|
|
23
|
+
}
|
|
24
|
+
function resolveManagedAgentWallet(input) {
|
|
25
|
+
const walletRegistry = input.walletRegistry ?? new walletRegistry_1.WalletRegistry();
|
|
26
|
+
const agentRegistry = input.agentRegistry ?? new agentRegistry_1.AgentRegistryStore(walletRegistry);
|
|
27
|
+
let wallet = walletRegistry.find(input.agentName);
|
|
28
|
+
let recoveryKey = null;
|
|
29
|
+
const createdWallet = !wallet;
|
|
30
|
+
if (!wallet) {
|
|
31
|
+
const provisioned = walletRegistry.create(input.agentName);
|
|
32
|
+
wallet = provisioned.record;
|
|
33
|
+
recoveryKey = provisioned.recoveryKey;
|
|
34
|
+
}
|
|
35
|
+
let agent = agentRegistry.find(input.agentName);
|
|
36
|
+
const createdAgent = !agent;
|
|
37
|
+
if (!agent) {
|
|
38
|
+
agent = agentRegistry.createAgent({
|
|
39
|
+
agentId: input.agentName,
|
|
40
|
+
ownerId: input.ownerId,
|
|
41
|
+
walletName: wallet.name
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
agent,
|
|
46
|
+
agentName: agent.name,
|
|
47
|
+
createdAgent,
|
|
48
|
+
createdWallet,
|
|
49
|
+
recoveryKey,
|
|
50
|
+
wallet,
|
|
51
|
+
walletManager: walletRegistry.toWalletManager(wallet.name)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function ensureManagedAgentWalletFunding(input) {
|
|
55
|
+
await (0, devnetFunding_1.ensureWalletHasMinimumSol)({
|
|
56
|
+
balanceService: input.balanceService,
|
|
57
|
+
fundingService: input.fundingService,
|
|
58
|
+
minimumSol: input.minimumSol,
|
|
59
|
+
publicKey: input.publicKey
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function logManagedAgentWallet(input) {
|
|
63
|
+
console.log(`Agent: ${input.agent.name}`);
|
|
64
|
+
if (input.agent.ownerId) {
|
|
65
|
+
console.log(`Owner: ${input.agent.ownerId}`);
|
|
66
|
+
}
|
|
67
|
+
console.log(`Wallet: ${input.wallet.publicKey}`);
|
|
68
|
+
console.log(`Wallet source: managed-registry`);
|
|
69
|
+
if (input.createdWallet) {
|
|
70
|
+
console.log("Wallet provisioning: created persistent wallet for agent");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log("Wallet provisioning: reused persistent wallet for agent");
|
|
74
|
+
}
|
|
75
|
+
if (input.createdAgent) {
|
|
76
|
+
console.log("Agent provisioning: created agent-to-wallet assignment");
|
|
77
|
+
}
|
|
78
|
+
if (input.recoveryKey) {
|
|
79
|
+
console.log(`Recovery key: ${input.recoveryKey}`);
|
|
80
|
+
}
|
|
81
|
+
}
|