@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,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runMultiAgentDevnetScenario = runMultiAgentDevnetScenario;
|
|
4
|
+
const AgentRunner_1 = require("../../agent/runner/AgentRunner");
|
|
5
|
+
const MemoHeartbeatStrategy_1 = require("../../agent/strategies/MemoHeartbeatStrategy");
|
|
6
|
+
const SimpleScriptedTransferStrategy_1 = require("../../agent/strategies/SimpleScriptedTransferStrategy");
|
|
7
|
+
const TreasuryDistributorStrategy_1 = require("../../agent/strategies/TreasuryDistributorStrategy");
|
|
8
|
+
const agentPolicies_1 = require("../../config/agentPolicies");
|
|
9
|
+
const env_1 = require("../../config/env");
|
|
10
|
+
const BalanceService_1 = require("../../core/balances/BalanceService");
|
|
11
|
+
const DevnetFundingService_1 = require("../../core/funding/DevnetFundingService");
|
|
12
|
+
const RpcClient_1 = require("../../core/rpc/RpcClient");
|
|
13
|
+
const TokenService_1 = require("../../core/tokens/TokenService");
|
|
14
|
+
const TransactionService_1 = require("../../core/transactions/TransactionService");
|
|
15
|
+
const managedAgentWallet_1 = require("../../scripts/managedAgentWallet");
|
|
16
|
+
const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
17
|
+
const DEMO_TRANSFER_SOL = 0.01;
|
|
18
|
+
const DEMO_TOKEN_DECIMALS = 6;
|
|
19
|
+
const DEMO_TOKEN_MINT_RAW = 10000000n;
|
|
20
|
+
const DEMO_TOKEN_DISTRIBUTION_RAW = 1000000n;
|
|
21
|
+
const TREASURY_MINIMUM_SOL = 0.5;
|
|
22
|
+
async function runMultiAgentDevnetScenario() {
|
|
23
|
+
const rpcClient = new RpcClient_1.RpcClient((0, env_1.getRpcUrl)(), "confirmed");
|
|
24
|
+
const transactionService = new TransactionService_1.TransactionService(rpcClient);
|
|
25
|
+
const tokenService = new TokenService_1.TokenService(rpcClient);
|
|
26
|
+
const fundingService = new DevnetFundingService_1.DevnetFundingService(rpcClient, transactionService);
|
|
27
|
+
const runner = new AgentRunner_1.AgentRunner();
|
|
28
|
+
const treasuryManaged = (0, managedAgentWallet_1.resolveManagedAgentWallet)({
|
|
29
|
+
agentName: "multi-agent-treasury",
|
|
30
|
+
ownerId: "multi-agent-devnet"
|
|
31
|
+
});
|
|
32
|
+
const treasuryWallet = treasuryManaged.walletManager;
|
|
33
|
+
const treasuryBalanceService = new BalanceService_1.BalanceService(rpcClient, tokenService);
|
|
34
|
+
await (0, managedAgentWallet_1.ensureManagedAgentWalletFunding)({
|
|
35
|
+
balanceService: treasuryBalanceService,
|
|
36
|
+
fundingService,
|
|
37
|
+
minimumSol: TREASURY_MINIMUM_SOL,
|
|
38
|
+
publicKey: treasuryWallet.publicKey
|
|
39
|
+
});
|
|
40
|
+
const managedAgents = [
|
|
41
|
+
(0, managedAgentWallet_1.resolveManagedAgentWallet)({ agentName: "multi-agent-1", ownerId: "multi-agent-devnet" }),
|
|
42
|
+
(0, managedAgentWallet_1.resolveManagedAgentWallet)({ agentName: "multi-agent-2", ownerId: "multi-agent-devnet" }),
|
|
43
|
+
(0, managedAgentWallet_1.resolveManagedAgentWallet)({ agentName: "multi-agent-3", ownerId: "multi-agent-devnet" })
|
|
44
|
+
];
|
|
45
|
+
const wallets = managedAgents.map((entry) => entry.walletManager);
|
|
46
|
+
for (const wallet of wallets) {
|
|
47
|
+
const transfer = await transactionService.buildTransaction({
|
|
48
|
+
feePayer: treasuryWallet.publicKey,
|
|
49
|
+
instructions: [
|
|
50
|
+
transactionService.buildSolTransferInstructionInSol({
|
|
51
|
+
from: treasuryWallet.publicKey,
|
|
52
|
+
to: wallet.publicKey,
|
|
53
|
+
amountSol: DEMO_TRANSFER_SOL
|
|
54
|
+
})
|
|
55
|
+
],
|
|
56
|
+
signer: treasuryWallet
|
|
57
|
+
});
|
|
58
|
+
await transactionService.sendAndConfirm(transfer);
|
|
59
|
+
}
|
|
60
|
+
const mintSetup = await tokenService.buildCreateMintInstructions({
|
|
61
|
+
payer: treasuryWallet.publicKey,
|
|
62
|
+
mintAuthority: treasuryWallet.publicKey,
|
|
63
|
+
decimals: DEMO_TOKEN_DECIMALS
|
|
64
|
+
});
|
|
65
|
+
const mintBuild = await transactionService.buildTransaction({
|
|
66
|
+
feePayer: treasuryWallet.publicKey,
|
|
67
|
+
instructions: mintSetup.instructions,
|
|
68
|
+
signer: treasuryWallet
|
|
69
|
+
});
|
|
70
|
+
mintBuild.transaction.sign([mintSetup.mintKeypair]);
|
|
71
|
+
await transactionService.sendAndConfirm(mintBuild);
|
|
72
|
+
const treasuryAta = await tokenService.ensureAtaInstruction({
|
|
73
|
+
mint: mintSetup.mintKeypair.publicKey,
|
|
74
|
+
owner: treasuryWallet.publicKey,
|
|
75
|
+
payer: treasuryWallet.publicKey
|
|
76
|
+
});
|
|
77
|
+
const mintInstructions = [
|
|
78
|
+
...(treasuryAta.createInstruction ? [treasuryAta.createInstruction] : []),
|
|
79
|
+
tokenService.buildMintToInstruction({
|
|
80
|
+
mint: mintSetup.mintKeypair.publicKey,
|
|
81
|
+
destinationAta: treasuryAta.address,
|
|
82
|
+
authority: treasuryWallet.publicKey,
|
|
83
|
+
amount: DEMO_TOKEN_MINT_RAW
|
|
84
|
+
})
|
|
85
|
+
];
|
|
86
|
+
const mintToTreasury = await transactionService.buildTransaction({
|
|
87
|
+
feePayer: treasuryWallet.publicKey,
|
|
88
|
+
instructions: mintInstructions,
|
|
89
|
+
signer: treasuryWallet
|
|
90
|
+
});
|
|
91
|
+
await transactionService.sendAndConfirm(mintToTreasury);
|
|
92
|
+
const recipients = wallets.map((wallet) => wallet.publicKey.toBase58());
|
|
93
|
+
const treasuryContext = {
|
|
94
|
+
id: treasuryManaged.agent.name,
|
|
95
|
+
walletManager: treasuryWallet,
|
|
96
|
+
walletPublicKey: treasuryWallet.publicKey,
|
|
97
|
+
rpcClient,
|
|
98
|
+
transactionService,
|
|
99
|
+
tokenService,
|
|
100
|
+
balanceService: treasuryBalanceService,
|
|
101
|
+
policyConfig: (0, agentPolicies_1.createDefaultPolicyConfig)({
|
|
102
|
+
agentId: treasuryManaged.agent.name,
|
|
103
|
+
allowedMints: [mintSetup.mintKeypair.publicKey.toBase58()],
|
|
104
|
+
allowedTransferDestinations: recipients
|
|
105
|
+
}),
|
|
106
|
+
logger: (message) => console.log(`[${treasuryManaged.agent.name}] ${message}`)
|
|
107
|
+
};
|
|
108
|
+
const transferContext = wallets.map((wallet, index) => ({
|
|
109
|
+
id: managedAgents[index].agent.name,
|
|
110
|
+
walletManager: wallet,
|
|
111
|
+
walletPublicKey: wallet.publicKey,
|
|
112
|
+
rpcClient,
|
|
113
|
+
transactionService,
|
|
114
|
+
tokenService,
|
|
115
|
+
balanceService: new BalanceService_1.BalanceService(rpcClient, tokenService),
|
|
116
|
+
policyConfig: (0, agentPolicies_1.createDefaultPolicyConfig)({
|
|
117
|
+
agentId: managedAgents[index].agent.name,
|
|
118
|
+
allowedMints: [mintSetup.mintKeypair.publicKey.toBase58()],
|
|
119
|
+
allowedTransferDestinations: [
|
|
120
|
+
treasuryWallet.publicKey.toBase58(),
|
|
121
|
+
...wallets.map((candidate) => candidate.publicKey.toBase58())
|
|
122
|
+
]
|
|
123
|
+
}),
|
|
124
|
+
logger: (message) => console.log(`[${managedAgents[index].agent.name}] ${message}`)
|
|
125
|
+
}));
|
|
126
|
+
runner.registerAgent({
|
|
127
|
+
context: treasuryContext,
|
|
128
|
+
strategy: new TreasuryDistributorStrategy_1.TreasuryDistributorStrategy({
|
|
129
|
+
mint: mintSetup.mintKeypair.publicKey.toBase58(),
|
|
130
|
+
recipients,
|
|
131
|
+
amountRawPerRecipient: DEMO_TOKEN_DISTRIBUTION_RAW
|
|
132
|
+
}),
|
|
133
|
+
approvalMode: "sandbox"
|
|
134
|
+
});
|
|
135
|
+
runner.registerAgent({
|
|
136
|
+
context: transferContext[0],
|
|
137
|
+
strategy: new SimpleScriptedTransferStrategy_1.SimpleScriptedTransferStrategy({
|
|
138
|
+
to: transferContext[1].walletPublicKey.toBase58(),
|
|
139
|
+
lamports: Math.round(0.001 * LAMPORTS_PER_SOL),
|
|
140
|
+
memo: "agent-1 scripted transfer"
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
runner.registerAgent({
|
|
144
|
+
context: transferContext[1],
|
|
145
|
+
strategy: new MemoHeartbeatStrategy_1.MemoHeartbeatStrategy()
|
|
146
|
+
});
|
|
147
|
+
runner.registerAgent({
|
|
148
|
+
context: transferContext[2],
|
|
149
|
+
strategy: new SimpleScriptedTransferStrategy_1.SimpleScriptedTransferStrategy({
|
|
150
|
+
to: treasuryWallet.publicKey.toBase58(),
|
|
151
|
+
lamports: Math.round(0.0005 * LAMPORTS_PER_SOL),
|
|
152
|
+
memo: "agent-3 return transfer"
|
|
153
|
+
})
|
|
154
|
+
});
|
|
155
|
+
const runResults = await runner.runOnceParallel();
|
|
156
|
+
const signatures = runResults.flatMap((result) => result.outcomes.flatMap((outcome) => (outcome.signature ? [outcome.signature] : [])));
|
|
157
|
+
for (const context of [treasuryContext, ...transferContext]) {
|
|
158
|
+
const sol = await context.balanceService.getSolBalance(context.walletPublicKey);
|
|
159
|
+
const spl = await context.balanceService.getSplTokenBalance({
|
|
160
|
+
owner: context.walletPublicKey,
|
|
161
|
+
mint: mintSetup.mintKeypair.publicKey
|
|
162
|
+
});
|
|
163
|
+
console.log(`${context.id} -> SOL: ${sol.toFixed(4)}, demo token: ${spl.toFixed(4)}`);
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
rpc: rpcClient.rpcUrl,
|
|
167
|
+
mintAddress: mintSetup.mintKeypair.publicKey.toBase58(),
|
|
168
|
+
signatures
|
|
169
|
+
};
|
|
170
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const multiAgentDevnetScenario_1 = require("../scenarios/multiAgentDevnetScenario");
|
|
4
|
+
async function main() {
|
|
5
|
+
console.log("PRKT multi-agent devnet demo");
|
|
6
|
+
const result = await (0, multiAgentDevnetScenario_1.runMultiAgentDevnetScenario)();
|
|
7
|
+
console.log(`RPC: ${result.rpc}`);
|
|
8
|
+
console.log(`Demo mint: ${result.mintAddress}`);
|
|
9
|
+
for (const signature of result.signatures) {
|
|
10
|
+
console.log(`tx: ${signature}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
main().catch((error) => {
|
|
14
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
15
|
+
console.error(`Multi-agent devnet demo failed: ${message}`);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JupiterSwapClient = exports.JupiterApiError = void 0;
|
|
4
|
+
class JupiterApiError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "JupiterApiError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.JupiterApiError = JupiterApiError;
|
|
11
|
+
class JupiterSwapClient {
|
|
12
|
+
baseUrl;
|
|
13
|
+
fetchImpl;
|
|
14
|
+
constructor(baseUrl, fetchImpl = fetch) {
|
|
15
|
+
this.baseUrl = baseUrl;
|
|
16
|
+
this.fetchImpl = fetchImpl;
|
|
17
|
+
}
|
|
18
|
+
async getQuote(input) {
|
|
19
|
+
const params = new URLSearchParams({
|
|
20
|
+
inputMint: input.inputMint,
|
|
21
|
+
outputMint: input.outputMint,
|
|
22
|
+
amount: input.amount.toString(),
|
|
23
|
+
slippageBps: input.slippageBps.toString()
|
|
24
|
+
});
|
|
25
|
+
const response = await this.fetchImpl(`${this.baseUrl}/swap/v1/quote?${params.toString()}`);
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
throw new JupiterApiError(`Jupiter quote failed with HTTP ${response.status}.`);
|
|
28
|
+
}
|
|
29
|
+
const payload = (await response.json());
|
|
30
|
+
const route = payload.data?.[0];
|
|
31
|
+
if (!route) {
|
|
32
|
+
throw new JupiterApiError("Jupiter quote returned no routes.");
|
|
33
|
+
}
|
|
34
|
+
return route;
|
|
35
|
+
}
|
|
36
|
+
async buildSwapTransaction(input) {
|
|
37
|
+
const response = await this.fetchImpl(`${this.baseUrl}/swap/v1/swap`, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: {
|
|
40
|
+
"content-type": "application/json"
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
quoteResponse: input.quoteResponse,
|
|
44
|
+
userPublicKey: input.userPublicKey.toBase58(),
|
|
45
|
+
wrapAndUnwrapSol: true,
|
|
46
|
+
dynamicComputeUnitLimit: true
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new JupiterApiError(`Jupiter swap build failed with HTTP ${response.status}.`);
|
|
51
|
+
}
|
|
52
|
+
const payload = (await response.json());
|
|
53
|
+
if (!payload.swapTransaction) {
|
|
54
|
+
throw new JupiterApiError("Jupiter swap response did not include a swapTransaction.");
|
|
55
|
+
}
|
|
56
|
+
return payload.swapTransaction;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.JupiterSwapClient = JupiterSwapClient;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SwapExecutor = void 0;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const WRAPPED_SOL_MINT = "So11111111111111111111111111111111111111112";
|
|
6
|
+
class SwapExecutor {
|
|
7
|
+
jupiterClient;
|
|
8
|
+
constructor(jupiterClient) {
|
|
9
|
+
this.jupiterClient = jupiterClient;
|
|
10
|
+
}
|
|
11
|
+
async buildSolToTokenSwapTransaction(input) {
|
|
12
|
+
const quote = await this.jupiterClient.getQuote({
|
|
13
|
+
inputMint: WRAPPED_SOL_MINT,
|
|
14
|
+
outputMint: input.outputMint,
|
|
15
|
+
amount: BigInt(Math.round(input.amountSol * web3_js_1.LAMPORTS_PER_SOL)),
|
|
16
|
+
slippageBps: input.slippageBps ?? 50
|
|
17
|
+
});
|
|
18
|
+
const swapTransactionBase64 = await this.jupiterClient.buildSwapTransaction({
|
|
19
|
+
quoteResponse: quote,
|
|
20
|
+
userPublicKey: input.walletManager.publicKey
|
|
21
|
+
});
|
|
22
|
+
const transaction = web3_js_1.VersionedTransaction.deserialize(Buffer.from(swapTransactionBase64, "base64"));
|
|
23
|
+
const signedTransaction = await input.walletManager.signTransaction(transaction);
|
|
24
|
+
return {
|
|
25
|
+
outputMint: input.outputMint,
|
|
26
|
+
quoteOutAmount: quote.outAmount,
|
|
27
|
+
routeType: "jupiter",
|
|
28
|
+
transaction: signedTransaction
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async executeSolToTokenSwap(input) {
|
|
32
|
+
const prepared = await this.buildSolToTokenSwapTransaction({
|
|
33
|
+
amountSol: input.amountSol,
|
|
34
|
+
outputMint: input.outputMint,
|
|
35
|
+
slippageBps: input.slippageBps,
|
|
36
|
+
walletManager: input.walletManager
|
|
37
|
+
});
|
|
38
|
+
const transaction = prepared.transaction;
|
|
39
|
+
input.policyGuard.validate(transaction);
|
|
40
|
+
const execution = await input.koraSigner.signAndSendGasless(transaction, `JUPITER_SWAP:${input.amountSol.toFixed(2)} SOL->${input.outputMint}`);
|
|
41
|
+
return {
|
|
42
|
+
execution,
|
|
43
|
+
outputMint: prepared.outputMint,
|
|
44
|
+
quoteOutAmount: prepared.quoteOutAmount,
|
|
45
|
+
routeType: prepared.routeType
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
static isLikelySolMint(mintAddress) {
|
|
49
|
+
return new web3_js_1.PublicKey(mintAddress).toBase58() === WRAPPED_SOL_MINT;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.SwapExecutor = SwapExecutor;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
const rpcUrl = (0, env_1.getRpcUrl)();
|
|
8
|
+
const connection = new web3_js_1.Connection(rpcUrl, "confirmed");
|
|
9
|
+
const walletManager = WalletManager_1.WalletManager.loadOrGenerate();
|
|
10
|
+
const { publicKey, source } = walletManager.toSafeSummary();
|
|
11
|
+
console.log("PRKT wallet ready.");
|
|
12
|
+
console.log(`RPC: ${rpcUrl}`);
|
|
13
|
+
console.log(`Wallet source: ${source}`);
|
|
14
|
+
console.log(`Devnet public key: ${publicKey}`);
|
|
15
|
+
const balanceLamports = await connection.getBalance(walletManager.publicKey);
|
|
16
|
+
console.log(`Devnet balance (lamports): ${balanceLamports}`);
|
|
17
|
+
}
|
|
18
|
+
main().catch((error) => {
|
|
19
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
20
|
+
console.error(`Startup failed: ${message}`);
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KoraRpcClient = exports.KoraRpcError = void 0;
|
|
4
|
+
class KoraRpcError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "KoraRpcError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.KoraRpcError = KoraRpcError;
|
|
11
|
+
class KoraRpcClient {
|
|
12
|
+
endpoint;
|
|
13
|
+
fetchImpl;
|
|
14
|
+
constructor(endpoint, fetchImpl = fetch) {
|
|
15
|
+
this.endpoint = endpoint;
|
|
16
|
+
this.fetchImpl = fetchImpl;
|
|
17
|
+
}
|
|
18
|
+
get rpcUrl() {
|
|
19
|
+
return this.endpoint;
|
|
20
|
+
}
|
|
21
|
+
async getBlockhash() {
|
|
22
|
+
const result = await this.call("getBlockhash", []);
|
|
23
|
+
const blockhash = result.blockhash ?? result.value?.blockhash;
|
|
24
|
+
if (!blockhash) {
|
|
25
|
+
throw new KoraRpcError("Kora getBlockhash response did not include a blockhash.");
|
|
26
|
+
}
|
|
27
|
+
return blockhash;
|
|
28
|
+
}
|
|
29
|
+
async signAndSendTransaction(transaction) {
|
|
30
|
+
const result = await this.call("signAndSendTransaction", [{ transaction }]);
|
|
31
|
+
const signature = result.signature ?? result.txid;
|
|
32
|
+
if (!signature) {
|
|
33
|
+
throw new KoraRpcError("Kora signAndSendTransaction response did not include a signature.");
|
|
34
|
+
}
|
|
35
|
+
return { signature };
|
|
36
|
+
}
|
|
37
|
+
async call(method, params) {
|
|
38
|
+
const response = await this.fetchImpl(this.endpoint, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: {
|
|
41
|
+
"content-type": "application/json"
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify({
|
|
44
|
+
jsonrpc: "2.0",
|
|
45
|
+
id: method,
|
|
46
|
+
method,
|
|
47
|
+
params
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new KoraRpcError(`Kora RPC request failed with HTTP ${response.status}.`);
|
|
52
|
+
}
|
|
53
|
+
const payload = (await response.json());
|
|
54
|
+
if ("error" in payload) {
|
|
55
|
+
throw new KoraRpcError(`Kora RPC error ${payload.error.code}: ${payload.error.message}`);
|
|
56
|
+
}
|
|
57
|
+
return payload.result;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.KoraRpcClient = KoraRpcClient;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KoraSigner = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const programs_1 = require("../solana/programs");
|
|
7
|
+
class KoraSigner {
|
|
8
|
+
client;
|
|
9
|
+
options;
|
|
10
|
+
constructor(client, options) {
|
|
11
|
+
this.client = client;
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
async buildMemoTransaction(walletManager, memo) {
|
|
15
|
+
const recentBlockhash = this.options.mockMode
|
|
16
|
+
? programs_1.MOCK_BLOCKHASH
|
|
17
|
+
: await this.client.getBlockhash();
|
|
18
|
+
const memoInstruction = new web3_js_1.TransactionInstruction({
|
|
19
|
+
programId: programs_1.MEMO_PROGRAM_ID,
|
|
20
|
+
keys: [],
|
|
21
|
+
data: Buffer.from(memo, "utf8")
|
|
22
|
+
});
|
|
23
|
+
const message = new web3_js_1.TransactionMessage({
|
|
24
|
+
payerKey: walletManager.publicKey,
|
|
25
|
+
recentBlockhash,
|
|
26
|
+
instructions: [memoInstruction]
|
|
27
|
+
}).compileToV0Message();
|
|
28
|
+
const transaction = new web3_js_1.VersionedTransaction(message);
|
|
29
|
+
return walletManager.signTransaction(transaction);
|
|
30
|
+
}
|
|
31
|
+
async signAndSendGasless(transaction, memo) {
|
|
32
|
+
const serializedTransaction = Buffer.from(transaction.serialize()).toString("base64");
|
|
33
|
+
if (this.options.mockMode) {
|
|
34
|
+
return {
|
|
35
|
+
endpoint: this.client.rpcUrl,
|
|
36
|
+
memo,
|
|
37
|
+
mock: true,
|
|
38
|
+
signature: this.createMockSignature(serializedTransaction)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const { signature } = await this.client.signAndSendTransaction(serializedTransaction);
|
|
42
|
+
return {
|
|
43
|
+
endpoint: this.client.rpcUrl,
|
|
44
|
+
memo,
|
|
45
|
+
mock: false,
|
|
46
|
+
signature
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async submitGaslessMemo(walletManager, memo) {
|
|
50
|
+
const transaction = await this.buildMemoTransaction(walletManager, memo);
|
|
51
|
+
return this.signAndSendGasless(transaction, memo);
|
|
52
|
+
}
|
|
53
|
+
createMockSignature(serializedTransaction) {
|
|
54
|
+
return (0, crypto_1.createHash)("sha256").update(serializedTransaction).digest("hex");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.KoraSigner = KoraSigner;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertGaslessDemoReadiness = assertGaslessDemoReadiness;
|
|
4
|
+
exports.parseUiAmount = parseUiAmount;
|
|
5
|
+
function assertGaslessDemoReadiness(input) {
|
|
6
|
+
if (input.solLamports !== 0) {
|
|
7
|
+
throw new Error("wallet:gasless requires the agent wallet to start with exactly 0 SOL so the fee abstraction claim is unambiguous.");
|
|
8
|
+
}
|
|
9
|
+
if (input.usdcBalance < 1) {
|
|
10
|
+
throw new Error("wallet:gasless requires at least 1.0 USDC in the agent wallet.");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function parseUiAmount(input) {
|
|
14
|
+
if (input.uiAmount !== null) {
|
|
15
|
+
return input.uiAmount;
|
|
16
|
+
}
|
|
17
|
+
return Number(input.amount) / 10 ** input.decimals;
|
|
18
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PolicyGuard = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
7
|
+
const emergencyLock_1 = require("./emergencyLock");
|
|
8
|
+
const programs_1 = require("../solana/programs");
|
|
9
|
+
class PolicyGuard {
|
|
10
|
+
policy;
|
|
11
|
+
constructor(policy) {
|
|
12
|
+
this.policy = policy;
|
|
13
|
+
}
|
|
14
|
+
validate(transaction) {
|
|
15
|
+
this.ensureEmergencyOverrideInactive();
|
|
16
|
+
this.ensureSessionActive();
|
|
17
|
+
const decompiledMessage = web3_js_1.TransactionMessage.decompile(transaction.message);
|
|
18
|
+
let totalSpendUnits = 0n;
|
|
19
|
+
for (const instruction of decompiledMessage.instructions) {
|
|
20
|
+
this.ensureProgramAllowed(instruction);
|
|
21
|
+
this.ensureInstructionShapeAllowed(instruction);
|
|
22
|
+
const spendDetails = this.tryDecodeSpend(instruction);
|
|
23
|
+
if (!spendDetails) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const destination = spendDetails.destination.toBase58();
|
|
27
|
+
if (!this.policy.whitelistedTransferDestinations.includes(destination)) {
|
|
28
|
+
throw new errors_1.SecurityViolationError(`Transfer blocked: destination ${destination} is not whitelisted.`);
|
|
29
|
+
}
|
|
30
|
+
totalSpendUnits += spendDetails.amount;
|
|
31
|
+
}
|
|
32
|
+
const maxSpendLamports = BigInt(this.policy.maxSpend.lamports);
|
|
33
|
+
if (totalSpendUnits > maxSpendLamports) {
|
|
34
|
+
throw new errors_1.SecurityViolationError(`Transfer blocked: ${totalSpendUnits} exceeds max spend ${maxSpendLamports}.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
ensureEmergencyOverrideInactive() {
|
|
38
|
+
const status = (0, emergencyLock_1.getEmergencyLockStatus)();
|
|
39
|
+
if (status.locked) {
|
|
40
|
+
throw new errors_1.SecurityViolationError(status.reason ?? "Human-in-the-loop Override engaged. Transaction execution is locked.");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
ensureSessionActive() {
|
|
44
|
+
const expiresAt = Date.parse(this.policy.sessionExpiry.iso8601);
|
|
45
|
+
if (Number.isNaN(expiresAt)) {
|
|
46
|
+
throw new errors_1.SecurityViolationError("Session blocked: invalid session expiry.");
|
|
47
|
+
}
|
|
48
|
+
if (Date.now() > expiresAt) {
|
|
49
|
+
throw new errors_1.SecurityViolationError("Session blocked: session has expired.");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
ensureProgramAllowed(instruction) {
|
|
53
|
+
const programId = instruction.programId.toBase58();
|
|
54
|
+
if (this.policy.whitelistedPrograms.includes(programId)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
throw new errors_1.SecurityViolationError(`Program blocked: ${programId} is not whitelisted.`);
|
|
58
|
+
}
|
|
59
|
+
tryDecodeSpend(instruction) {
|
|
60
|
+
if (instruction.programId.equals(web3_js_1.SystemProgram.programId)) {
|
|
61
|
+
try {
|
|
62
|
+
const transfer = web3_js_1.SystemInstruction.decodeTransfer(instruction);
|
|
63
|
+
return {
|
|
64
|
+
amount: transfer.lamports,
|
|
65
|
+
destination: transfer.toPubkey
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Parse SPL token spend instructions so token outflows are policy-constrained.
|
|
73
|
+
try {
|
|
74
|
+
const transfer = (0, spl_token_1.decodeTransferInstruction)(instruction);
|
|
75
|
+
return {
|
|
76
|
+
amount: BigInt(transfer.data.amount.toString()),
|
|
77
|
+
destination: transfer.keys.destination.pubkey
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Not a Transfer instruction.
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const transferChecked = (0, spl_token_1.decodeTransferCheckedInstruction)(instruction);
|
|
85
|
+
return {
|
|
86
|
+
amount: BigInt(transferChecked.data.amount.toString()),
|
|
87
|
+
destination: transferChecked.keys.destination.pubkey
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Not a TransferChecked instruction.
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
ensureInstructionShapeAllowed(instruction) {
|
|
96
|
+
const blockedVector = this.detectBlockedSpendVector(instruction);
|
|
97
|
+
if (blockedVector) {
|
|
98
|
+
throw new errors_1.SecurityViolationError(blockedVector);
|
|
99
|
+
}
|
|
100
|
+
if (this.tryDecodeSpend(instruction)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const programId = instruction.programId.toBase58();
|
|
104
|
+
const knownNonSpendPrograms = [
|
|
105
|
+
web3_js_1.SystemProgram.programId.toBase58(),
|
|
106
|
+
programs_1.TOKEN_PROGRAM_ID.toBase58(),
|
|
107
|
+
programs_1.ASSOCIATED_TOKEN_PROGRAM_ID.toBase58(),
|
|
108
|
+
programs_1.MEMO_PROGRAM_ID.toBase58()
|
|
109
|
+
];
|
|
110
|
+
if (knownNonSpendPrograms.includes(programId)) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
throw new errors_1.SecurityViolationError(`Opaque instruction blocked: ${programId} is not explicitly approved.`);
|
|
114
|
+
}
|
|
115
|
+
detectBlockedSpendVector(instruction) {
|
|
116
|
+
try {
|
|
117
|
+
const approve = (0, spl_token_1.decodeApproveInstruction)(instruction);
|
|
118
|
+
return `Delegate approval blocked: ${approve.keys.delegate.pubkey.toBase58()}`;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// ignore
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const approveChecked = (0, spl_token_1.decodeApproveCheckedInstruction)(instruction);
|
|
125
|
+
return `Delegate approval blocked: ${approveChecked.keys.delegate.pubkey.toBase58()}`;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// ignore
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const revoke = (0, spl_token_1.decodeRevokeInstruction)(instruction);
|
|
132
|
+
return `Delegate revoke requires explicit approval: ${revoke.keys.account.pubkey.toBase58()}`;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// ignore
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const closeAccount = (0, spl_token_1.decodeCloseAccountInstruction)(instruction);
|
|
139
|
+
return `Close-account drain blocked: ${closeAccount.keys.destination.pubkey.toBase58()}`;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// ignore
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const setAuthority = (0, spl_token_1.decodeSetAuthorityInstruction)(instruction);
|
|
146
|
+
if (setAuthority.data.authorityType === spl_token_1.AuthorityType.AccountOwner ||
|
|
147
|
+
setAuthority.data.authorityType === spl_token_1.AuthorityType.CloseAccount ||
|
|
148
|
+
setAuthority.data.authorityType === spl_token_1.AuthorityType.MintTokens) {
|
|
149
|
+
return `Authority change blocked: ${spl_token_1.AuthorityType[setAuthority.data.authorityType]}`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// ignore
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.PolicyGuard = PolicyGuard;
|