@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,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UniversalDeFiOrchestrator = void 0;
|
|
4
|
+
const policyFactory_1 = require("../../agent/policyFactory");
|
|
5
|
+
const env_1 = require("../../config/env");
|
|
6
|
+
const DeFiExecutor_1 = require("../DeFiExecutor");
|
|
7
|
+
const adapters_1 = require("./adapters");
|
|
8
|
+
const liveExecutors_1 = require("./liveExecutors");
|
|
9
|
+
class UniversalDeFiOrchestrator {
|
|
10
|
+
deps;
|
|
11
|
+
adapters;
|
|
12
|
+
executor;
|
|
13
|
+
constructor(deps, adapters) {
|
|
14
|
+
this.deps = deps;
|
|
15
|
+
this.adapters = adapters ?? [
|
|
16
|
+
new adapters_1.JupiterUniversalAdapter(),
|
|
17
|
+
new adapters_1.MarinadeUniversalAdapter(),
|
|
18
|
+
new adapters_1.RaydiumUniversalAdapter(),
|
|
19
|
+
new adapters_1.KaminoUniversalAdapter()
|
|
20
|
+
];
|
|
21
|
+
this.executor = new DeFiExecutor_1.DeFiExecutor(deps.policy ??
|
|
22
|
+
(0, policyFactory_1.createDefaultAgentPolicy)({
|
|
23
|
+
maxSpend: {
|
|
24
|
+
lamports: 2_000_000_000
|
|
25
|
+
}
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
async execute(request, options) {
|
|
29
|
+
const adapter = this.resolveAdapter(request);
|
|
30
|
+
if (!adapter) {
|
|
31
|
+
this.log(`No compatible adapter for capability=${request.capability} protocol=${request.protocol ?? "auto"}`);
|
|
32
|
+
return {
|
|
33
|
+
capability: request.capability,
|
|
34
|
+
protocol: request.protocol ?? "raydium",
|
|
35
|
+
result: null
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const intent = adapter.buildIntent(request);
|
|
39
|
+
if (!intent) {
|
|
40
|
+
this.log(`${adapter.protocol} returned HOLD for capability ${request.capability}`);
|
|
41
|
+
return {
|
|
42
|
+
capability: request.capability,
|
|
43
|
+
protocol: adapter.protocol,
|
|
44
|
+
result: null
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const liveFirst = this.deps.liveFirst ?? (0, env_1.isUniversalDeFiLiveFirstEnabled)();
|
|
48
|
+
if (liveFirst) {
|
|
49
|
+
const preparedLive = (await (0, liveExecutors_1.prepareLiveJupiter)({
|
|
50
|
+
intent,
|
|
51
|
+
logger: this.deps.logger,
|
|
52
|
+
walletManager: this.deps.walletManager
|
|
53
|
+
})) ??
|
|
54
|
+
(await (0, liveExecutors_1.prepareLiveRaydiumLp)({
|
|
55
|
+
intent,
|
|
56
|
+
logger: this.deps.logger,
|
|
57
|
+
walletManager: this.deps.walletManager
|
|
58
|
+
})) ??
|
|
59
|
+
(await (0, liveExecutors_1.prepareLiveKamino)({
|
|
60
|
+
intent,
|
|
61
|
+
logger: this.deps.logger,
|
|
62
|
+
walletManager: this.deps.walletManager
|
|
63
|
+
})) ??
|
|
64
|
+
(await (0, liveExecutors_1.prepareLiveMarinade)({
|
|
65
|
+
intent,
|
|
66
|
+
logger: this.deps.logger,
|
|
67
|
+
walletManager: this.deps.walletManager
|
|
68
|
+
}));
|
|
69
|
+
const liveResult = await this.tryExecutePreparedLive(preparedLive, options);
|
|
70
|
+
if (liveResult) {
|
|
71
|
+
return {
|
|
72
|
+
capability: request.capability,
|
|
73
|
+
protocol: adapter.protocol,
|
|
74
|
+
result: liveResult
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const result = await this.executor.executeIntent({
|
|
79
|
+
intent,
|
|
80
|
+
koraSigner: this.deps.koraSigner,
|
|
81
|
+
walletManager: this.deps.walletManager
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
capability: request.capability,
|
|
85
|
+
protocol: adapter.protocol,
|
|
86
|
+
result
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async executeBatch(requests, options) {
|
|
90
|
+
return Promise.all(requests.map((request) => this.execute(request, options)));
|
|
91
|
+
}
|
|
92
|
+
resolveAdapter(request) {
|
|
93
|
+
const scoped = request.protocol
|
|
94
|
+
? this.adapters.filter((adapter) => adapter.protocol === request.protocol)
|
|
95
|
+
: this.adapters;
|
|
96
|
+
return scoped.find((adapter) => adapter.capabilities.includes(request.capability)) ?? null;
|
|
97
|
+
}
|
|
98
|
+
log(message) {
|
|
99
|
+
(this.deps.logger ?? (() => undefined))(message);
|
|
100
|
+
}
|
|
101
|
+
async tryExecutePreparedLive(prepared, options) {
|
|
102
|
+
if (!prepared) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (!options?.liveExecutor) {
|
|
106
|
+
this.log(`guarded live ${prepared.protocol} transaction prepared but no guarded executor was provided`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const execution = await options.liveExecutor.executePreparedTransaction({
|
|
110
|
+
confirmationStrategy: prepared.confirmationStrategy,
|
|
111
|
+
inspectionContext: prepared.inspectionContext,
|
|
112
|
+
policyConfigPatch: prepared.policyConfigPatch,
|
|
113
|
+
transaction: prepared.transaction
|
|
114
|
+
});
|
|
115
|
+
if (!execution.signature) {
|
|
116
|
+
const reasons = execution.inspection.reasons.join("; ");
|
|
117
|
+
this.log(`guarded live ${prepared.protocol} execution blocked${reasons ? `: ${reasons}` : ""}`);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
if (prepared.verifyExecution) {
|
|
121
|
+
await prepared.verifyExecution(execution.signature);
|
|
122
|
+
}
|
|
123
|
+
return prepared.toExecutionResult(execution.signature);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.UniversalDeFiOrchestrator = UniversalDeFiOrchestrator;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KaminoUniversalAdapter = exports.RaydiumUniversalAdapter = exports.MarinadeUniversalAdapter = exports.JupiterUniversalAdapter = void 0;
|
|
4
|
+
const JupiterAdapter_1 = require("../adapters/JupiterAdapter");
|
|
5
|
+
const KaminoAdapter_1 = require("../adapters/KaminoAdapter");
|
|
6
|
+
const MarinadeAdapter_1 = require("../adapters/MarinadeAdapter");
|
|
7
|
+
const RaydiumAdapter_1 = require("../adapters/RaydiumAdapter");
|
|
8
|
+
class JupiterUniversalAdapter {
|
|
9
|
+
protocol = "jupiter";
|
|
10
|
+
capabilities = ["trade"];
|
|
11
|
+
adapter = new JupiterAdapter_1.JupiterAdapter();
|
|
12
|
+
buildIntent(request) {
|
|
13
|
+
if (request.capability !== "trade") {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return this.adapter.buildTradeIntent(request.snapshot);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.JupiterUniversalAdapter = JupiterUniversalAdapter;
|
|
20
|
+
class MarinadeUniversalAdapter {
|
|
21
|
+
protocol = "marinade";
|
|
22
|
+
capabilities = ["staking"];
|
|
23
|
+
adapter = new MarinadeAdapter_1.MarinadeAdapter();
|
|
24
|
+
buildIntent(request) {
|
|
25
|
+
if (request.capability !== "staking") {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return this.adapter.buildStakeIntent(request.snapshot);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.MarinadeUniversalAdapter = MarinadeUniversalAdapter;
|
|
32
|
+
class RaydiumUniversalAdapter {
|
|
33
|
+
protocol = "raydium";
|
|
34
|
+
capabilities = ["lp", "yield"];
|
|
35
|
+
adapter = new RaydiumAdapter_1.RaydiumAdapter();
|
|
36
|
+
buildIntent(request) {
|
|
37
|
+
if (request.capability === "lp") {
|
|
38
|
+
return this.adapter.buildAddLiquidityIntent(request.snapshot);
|
|
39
|
+
}
|
|
40
|
+
if (request.capability === "yield") {
|
|
41
|
+
const rewards = request.snapshot.rewardsClaimableAtomic ?? 0;
|
|
42
|
+
if (rewards <= 0) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const plan = this.adapter.buildAddLiquidityPlan();
|
|
46
|
+
return {
|
|
47
|
+
action: "harvest",
|
|
48
|
+
amountLamports: 0,
|
|
49
|
+
marketId: plan.poolId,
|
|
50
|
+
memo: `DEFI_INTENT:RAYDIUM:harvest:${rewards}`,
|
|
51
|
+
protocol: this.protocol,
|
|
52
|
+
slippageBps: plan.slippageBps
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.RaydiumUniversalAdapter = RaydiumUniversalAdapter;
|
|
59
|
+
class KaminoUniversalAdapter {
|
|
60
|
+
protocol = "kamino";
|
|
61
|
+
capabilities = ["lending", "borrowing", "yield"];
|
|
62
|
+
adapter = new KaminoAdapter_1.KaminoAdapter();
|
|
63
|
+
buildIntent(request) {
|
|
64
|
+
if (request.capability === "borrowing") {
|
|
65
|
+
return this.adapter.buildBorrowIntent(request.snapshot);
|
|
66
|
+
}
|
|
67
|
+
if (request.capability !== "lending" && request.capability !== "yield") {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return this.adapter.buildDepositIntent(request.snapshot);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.KaminoUniversalAdapter = KaminoUniversalAdapter;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UniversalDeFiOrchestrator = void 0;
|
|
4
|
+
var UniversalDeFiOrchestrator_1 = require("./UniversalDeFiOrchestrator");
|
|
5
|
+
Object.defineProperty(exports, "UniversalDeFiOrchestrator", { enumerable: true, get: function () { return UniversalDeFiOrchestrator_1.UniversalDeFiOrchestrator; } });
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prepareLiveJupiter = prepareLiveJupiter;
|
|
4
|
+
exports.prepareLiveRaydiumLp = prepareLiveRaydiumLp;
|
|
5
|
+
exports.prepareLiveKamino = prepareLiveKamino;
|
|
6
|
+
exports.prepareLiveMarinade = prepareLiveMarinade;
|
|
7
|
+
const kit_1 = require("@solana/kit");
|
|
8
|
+
const marinade_ts_sdk_1 = require("@marinade.finance/marinade-ts-sdk");
|
|
9
|
+
const klend_sdk_1 = require("@kamino-finance/klend-sdk");
|
|
10
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
11
|
+
const env_1 = require("../../config/env");
|
|
12
|
+
const RpcClient_1 = require("../../core/rpc/RpcClient");
|
|
13
|
+
const PostTransactionVerifier_1 = require("../../core/transactions/PostTransactionVerifier");
|
|
14
|
+
const TokenService_1 = require("../../core/tokens/TokenService");
|
|
15
|
+
const JupiterSwapClient_1 = require("../../dex/JupiterSwapClient");
|
|
16
|
+
const SwapExecutor_1 = require("../../dex/SwapExecutor");
|
|
17
|
+
const raydiumDevnetConfig_1 = require("../lp/raydiumDevnetConfig");
|
|
18
|
+
const RaydiumAdapter_1 = require("../adapters/RaydiumAdapter");
|
|
19
|
+
const kaminoInstructionCompat_1 = require("../kamino/kaminoInstructionCompat");
|
|
20
|
+
const kaminoLiveConfig_1 = require("../kamino/kaminoLiveConfig");
|
|
21
|
+
const loadKaminoMarketWithFallback_1 = require("../kamino/loadKaminoMarketWithFallback");
|
|
22
|
+
async function prepareLiveJupiter(input) {
|
|
23
|
+
if (input.intent.protocol !== "jupiter" || input.intent.action !== "trade") {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (!(0, env_1.isLiveSwapPathEnabled)()) {
|
|
27
|
+
input.logger?.("live jupiter disabled via ENABLE_LIVE_SWAP_PATH");
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const amountSol = input.intent.amountLamports / web3_js_1.LAMPORTS_PER_SOL;
|
|
31
|
+
const outputMint = (0, env_1.getUsdcMintAddress)();
|
|
32
|
+
const rpcClient = new RpcClient_1.RpcClient((0, env_1.getRpcUrl)(), "confirmed");
|
|
33
|
+
const tokenService = new TokenService_1.TokenService(rpcClient);
|
|
34
|
+
const verifier = new PostTransactionVerifier_1.PostTransactionVerifier(rpcClient, tokenService);
|
|
35
|
+
const outputSnapshot = await verifier.snapshotSplBalanceForOwner({
|
|
36
|
+
label: `Jupiter output token balance (${outputMint})`,
|
|
37
|
+
mint: new web3_js_1.PublicKey(outputMint),
|
|
38
|
+
owner: input.walletManager.publicKey
|
|
39
|
+
});
|
|
40
|
+
const swapExecutor = new SwapExecutor_1.SwapExecutor(new JupiterSwapClient_1.JupiterSwapClient((0, env_1.getJupiterApiBaseUrl)()));
|
|
41
|
+
const prepared = await swapExecutor.buildSolToTokenSwapTransaction({
|
|
42
|
+
amountSol,
|
|
43
|
+
outputMint,
|
|
44
|
+
slippageBps: input.intent.slippageBps,
|
|
45
|
+
walletManager: input.walletManager
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
protocol: input.intent.protocol,
|
|
49
|
+
toExecutionResult(signature) {
|
|
50
|
+
return {
|
|
51
|
+
action: input.intent.action,
|
|
52
|
+
memo: `LIVE:JUPITER:${input.intent.marketId}:${input.intent.amountLamports}`,
|
|
53
|
+
mock: false,
|
|
54
|
+
protocol: input.intent.protocol,
|
|
55
|
+
signature
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
transaction: prepared.transaction,
|
|
59
|
+
async verifyExecution(signature) {
|
|
60
|
+
const [report] = await verifier.assertBalanceChanges([
|
|
61
|
+
{
|
|
62
|
+
minIncreaseRaw: 1n,
|
|
63
|
+
snapshot: outputSnapshot
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
input.logger?.(`verified ${signature}: ${report.label} ${report.beforeUi} -> ${report.afterUi} (${report.deltaUi})`);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function prepareLiveRaydiumLp(input) {
|
|
71
|
+
if (input.intent.protocol !== "raydium" || input.intent.action !== "add_liquidity") {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (!(0, env_1.isLiveRaydiumLpEnabled)()) {
|
|
75
|
+
input.logger?.("live raydium disabled via ENABLE_LIVE_RAYDIUM_LP");
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const rpcUrl = (0, env_1.getRpcUrl)();
|
|
79
|
+
const cluster = (0, env_1.detectClusterFromRpcUrl)(rpcUrl);
|
|
80
|
+
if (cluster !== "devnet" && cluster !== "unknown") {
|
|
81
|
+
input.logger?.(`live raydium lp currently intended for devnet; current cluster=${cluster}`);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const connection = new web3_js_1.Connection(rpcUrl, "confirmed");
|
|
85
|
+
const rpcClient = new RpcClient_1.RpcClient(rpcUrl, "confirmed");
|
|
86
|
+
const tokenService = new TokenService_1.TokenService(rpcClient);
|
|
87
|
+
const verifier = new PostTransactionVerifier_1.PostTransactionVerifier(rpcClient, tokenService);
|
|
88
|
+
const config = (0, raydiumDevnetConfig_1.loadRaydiumLpDevnetConfig)();
|
|
89
|
+
const adapter = new RaydiumAdapter_1.RaydiumAdapter();
|
|
90
|
+
const requiredAccounts = [
|
|
91
|
+
config.poolConfig.poolId,
|
|
92
|
+
config.poolConfig.authority,
|
|
93
|
+
config.poolConfig.baseVault,
|
|
94
|
+
config.poolConfig.quoteVault,
|
|
95
|
+
config.poolConfig.openOrders,
|
|
96
|
+
config.poolConfig.targetOrders,
|
|
97
|
+
config.poolConfig.marketId,
|
|
98
|
+
config.poolConfig.marketEventQueue,
|
|
99
|
+
config.poolConfig.lpMint,
|
|
100
|
+
config.userTokenAccounts.baseTokenAccount,
|
|
101
|
+
config.userTokenAccounts.quoteTokenAccount,
|
|
102
|
+
config.userTokenAccounts.lpTokenAccount
|
|
103
|
+
];
|
|
104
|
+
const accountInfos = await connection.getMultipleAccountsInfo(requiredAccounts.map((key) => new web3_js_1.PublicKey(key)), "confirmed");
|
|
105
|
+
const missing = requiredAccounts.filter((_, index) => accountInfos[index] === null);
|
|
106
|
+
if (missing.length > 0) {
|
|
107
|
+
input.logger?.(`live raydium config invalid on cluster; missing ${missing.length} accounts`);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const latestBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
111
|
+
const lpBalanceSnapshot = await verifier.snapshotSplTokenAccount({
|
|
112
|
+
label: "Raydium LP token balance",
|
|
113
|
+
mint: new web3_js_1.PublicKey(config.poolConfig.lpMint),
|
|
114
|
+
tokenAccount: new web3_js_1.PublicKey(config.userTokenAccounts.lpTokenAccount)
|
|
115
|
+
});
|
|
116
|
+
const transaction = await adapter.buildAddLiquidityTransactionDraft({
|
|
117
|
+
baseAmountIn: config.amounts.baseAmountIn,
|
|
118
|
+
otherAmountMin: config.amounts.otherAmountMin,
|
|
119
|
+
owner: input.walletManager,
|
|
120
|
+
poolConfig: config.poolConfig,
|
|
121
|
+
quoteAmountIn: config.amounts.quoteAmountIn,
|
|
122
|
+
recentBlockhash: latestBlockhash.blockhash,
|
|
123
|
+
userTokenAccounts: config.userTokenAccounts
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
confirmationStrategy: {
|
|
127
|
+
blockhash: latestBlockhash.blockhash,
|
|
128
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
129
|
+
signature: ""
|
|
130
|
+
},
|
|
131
|
+
protocol: input.intent.protocol,
|
|
132
|
+
policyConfigPatch: {
|
|
133
|
+
rules: {
|
|
134
|
+
allowOpaqueProgramIds: [config.poolConfig.programId],
|
|
135
|
+
allowedProgramIds: [config.poolConfig.programId]
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
toExecutionResult(signature) {
|
|
139
|
+
return {
|
|
140
|
+
action: input.intent.action,
|
|
141
|
+
memo: `LIVE:RAYDIUM:${config.poolConfig.poolId}`,
|
|
142
|
+
mock: false,
|
|
143
|
+
protocol: input.intent.protocol,
|
|
144
|
+
signature
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
transaction,
|
|
148
|
+
async verifyExecution(signature) {
|
|
149
|
+
const [report] = await verifier.assertBalanceChanges([
|
|
150
|
+
{
|
|
151
|
+
minIncreaseRaw: 1n,
|
|
152
|
+
snapshot: lpBalanceSnapshot
|
|
153
|
+
}
|
|
154
|
+
]);
|
|
155
|
+
input.logger?.(`verified ${signature}: ${report.label} ${report.beforeUi} -> ${report.afterUi} (${report.deltaUi})`);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async function prepareLiveKamino(input) {
|
|
160
|
+
if (input.intent.protocol !== "kamino" ||
|
|
161
|
+
(input.intent.action !== "deposit" && input.intent.action !== "borrow")) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
if (!(0, env_1.isLiveKaminoEnabled)()) {
|
|
165
|
+
input.logger?.("live kamino disabled via ENABLE_LIVE_KAMINO");
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const rpcUrl = (0, env_1.getRpcUrl)();
|
|
169
|
+
const cluster = (0, env_1.detectClusterFromRpcUrl)(rpcUrl);
|
|
170
|
+
const config = (0, kaminoLiveConfig_1.loadKaminoLiveConfig)();
|
|
171
|
+
if (config.cluster && cluster !== "unknown" && cluster !== config.cluster) {
|
|
172
|
+
throw new Error(`Kamino live config cluster=${config.cluster} does not match current RPC cluster=${cluster}. Check ${(0, env_1.getKaminoLiveConfigPath)()}.`);
|
|
173
|
+
}
|
|
174
|
+
const rpcClient = new RpcClient_1.RpcClient(rpcUrl, "confirmed");
|
|
175
|
+
const tokenService = new TokenService_1.TokenService(rpcClient);
|
|
176
|
+
const verifier = new PostTransactionVerifier_1.PostTransactionVerifier(rpcClient, tokenService);
|
|
177
|
+
const connection = new web3_js_1.Connection(rpcUrl, "confirmed");
|
|
178
|
+
const latestBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
179
|
+
const configuredMarketAddress = new web3_js_1.PublicKey(config.marketAddress);
|
|
180
|
+
const configuredProgramId = new web3_js_1.PublicKey(config.programId);
|
|
181
|
+
const marketAccount = await rpcClient.getAccountInfo(configuredMarketAddress, "confirmed");
|
|
182
|
+
if (!marketAccount) {
|
|
183
|
+
throw new Error(`Kamino market ${config.marketAddress} does not exist on ${rpcUrl}. Update ${(0, env_1.getKaminoLiveConfigPath)()} with a valid market address for this cluster.`);
|
|
184
|
+
}
|
|
185
|
+
if (!marketAccount.owner.equals(configuredProgramId)) {
|
|
186
|
+
throw new Error(`Kamino market ${config.marketAddress} is owned by ${marketAccount.owner.toBase58()}, not Kamino program ${config.programId}. Update ${(0, env_1.getKaminoLiveConfigPath)()} with a valid market address for this cluster.`);
|
|
187
|
+
}
|
|
188
|
+
const ownerAddress = (0, kit_1.address)(input.walletManager.publicKey.toBase58());
|
|
189
|
+
const ownerSigner = (0, kit_1.createNoopSigner)(ownerAddress);
|
|
190
|
+
const programAddress = (0, kit_1.address)(config.programId);
|
|
191
|
+
const marketAddress = (0, kit_1.address)(config.marketAddress);
|
|
192
|
+
const obligationType = new klend_sdk_1.VanillaObligation(programAddress);
|
|
193
|
+
const market = await (0, loadKaminoMarketWithFallback_1.loadKaminoMarketWithFallback)({
|
|
194
|
+
cluster,
|
|
195
|
+
logger: input.logger,
|
|
196
|
+
marketAddress,
|
|
197
|
+
programAddress,
|
|
198
|
+
rpcUrl
|
|
199
|
+
});
|
|
200
|
+
if (input.intent.action === "deposit") {
|
|
201
|
+
const depositMint = (0, kit_1.address)(config.depositMint);
|
|
202
|
+
market.getExistingReserveByMint(depositMint, "configured deposit mint");
|
|
203
|
+
const beforeDeposit = await market.getObligationDepositByWallet(ownerAddress, depositMint, obligationType);
|
|
204
|
+
const action = await klend_sdk_1.KaminoAction.buildDepositTxns(market, config.actions.depositAmountRaw.toString(), depositMint, ownerSigner, obligationType, true, undefined, 0, true, false, {
|
|
205
|
+
skipInitialization: false,
|
|
206
|
+
skipLutCreation: true
|
|
207
|
+
});
|
|
208
|
+
return {
|
|
209
|
+
confirmationStrategy: {
|
|
210
|
+
blockhash: latestBlockhash.blockhash,
|
|
211
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
212
|
+
signature: ""
|
|
213
|
+
},
|
|
214
|
+
protocol: input.intent.protocol,
|
|
215
|
+
policyConfigPatch: {
|
|
216
|
+
rules: {
|
|
217
|
+
allowedCloseAccountDestinations: [input.walletManager.publicKey.toBase58()],
|
|
218
|
+
allowOpaqueProgramIds: [config.programId],
|
|
219
|
+
allowedProgramIds: [config.programId]
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
toExecutionResult(signature) {
|
|
223
|
+
return {
|
|
224
|
+
action: input.intent.action,
|
|
225
|
+
memo: `LIVE:KAMINO:deposit:${config.marketAddress}:${config.depositMint}`,
|
|
226
|
+
mock: false,
|
|
227
|
+
protocol: input.intent.protocol,
|
|
228
|
+
signature
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
transaction: await buildSignedVersionedTransaction({
|
|
232
|
+
instructions: buildKaminoInstructions(action, cluster, input.logger),
|
|
233
|
+
payer: input.walletManager.publicKey,
|
|
234
|
+
recentBlockhash: latestBlockhash.blockhash,
|
|
235
|
+
walletManager: input.walletManager
|
|
236
|
+
}),
|
|
237
|
+
async verifyExecution(signature) {
|
|
238
|
+
const afterDeposit = await market.getObligationDepositByWallet(ownerAddress, depositMint, obligationType);
|
|
239
|
+
if (!afterDeposit.greaterThan(beforeDeposit)) {
|
|
240
|
+
throw new Error(`Kamino deposit verification failed: obligation deposit did not increase (${beforeDeposit.toString()} -> ${afterDeposit.toString()}).`);
|
|
241
|
+
}
|
|
242
|
+
input.logger?.(`verified ${signature}: Kamino obligation deposit ${beforeDeposit.toString()} -> ${afterDeposit.toString()} (${afterDeposit.minus(beforeDeposit).toString()})`);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const borrowMint = (0, kit_1.address)(config.borrowMint);
|
|
247
|
+
market.getExistingReserveByMint(borrowMint, "configured borrow mint");
|
|
248
|
+
const beforeBorrow = await market.getObligationBorrowByWallet(ownerAddress, borrowMint, obligationType);
|
|
249
|
+
const borrowSnapshot = await verifier.snapshotSplBalanceForOwner({
|
|
250
|
+
label: `Kamino borrowed token balance (${config.borrowMint})`,
|
|
251
|
+
mint: new web3_js_1.PublicKey(config.borrowMint),
|
|
252
|
+
owner: input.walletManager.publicKey
|
|
253
|
+
});
|
|
254
|
+
const action = await klend_sdk_1.KaminoAction.buildBorrowTxns(market, config.actions.borrowAmountRaw.toString(), borrowMint, ownerSigner, obligationType, true, undefined, 0, true, false, {
|
|
255
|
+
skipInitialization: false,
|
|
256
|
+
skipLutCreation: true
|
|
257
|
+
});
|
|
258
|
+
return {
|
|
259
|
+
confirmationStrategy: {
|
|
260
|
+
blockhash: latestBlockhash.blockhash,
|
|
261
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
262
|
+
signature: ""
|
|
263
|
+
},
|
|
264
|
+
protocol: input.intent.protocol,
|
|
265
|
+
policyConfigPatch: {
|
|
266
|
+
rules: {
|
|
267
|
+
allowedCloseAccountDestinations: [input.walletManager.publicKey.toBase58()],
|
|
268
|
+
allowOpaqueProgramIds: [config.programId],
|
|
269
|
+
allowedProgramIds: [config.programId]
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
toExecutionResult(signature) {
|
|
273
|
+
return {
|
|
274
|
+
action: input.intent.action,
|
|
275
|
+
memo: `LIVE:KAMINO:borrow:${config.marketAddress}:${config.borrowMint}`,
|
|
276
|
+
mock: false,
|
|
277
|
+
protocol: input.intent.protocol,
|
|
278
|
+
signature
|
|
279
|
+
};
|
|
280
|
+
},
|
|
281
|
+
transaction: await buildSignedVersionedTransaction({
|
|
282
|
+
instructions: buildKaminoInstructions(action, cluster, input.logger),
|
|
283
|
+
payer: input.walletManager.publicKey,
|
|
284
|
+
recentBlockhash: latestBlockhash.blockhash,
|
|
285
|
+
walletManager: input.walletManager
|
|
286
|
+
}),
|
|
287
|
+
async verifyExecution(signature) {
|
|
288
|
+
const afterBorrow = await market.getObligationBorrowByWallet(ownerAddress, borrowMint, obligationType);
|
|
289
|
+
if (!afterBorrow.greaterThan(beforeBorrow)) {
|
|
290
|
+
throw new Error(`Kamino borrow verification failed: obligation borrow did not increase (${beforeBorrow.toString()} -> ${afterBorrow.toString()}).`);
|
|
291
|
+
}
|
|
292
|
+
const [report] = await verifier.assertBalanceChanges([
|
|
293
|
+
{
|
|
294
|
+
minIncreaseRaw: 1n,
|
|
295
|
+
snapshot: borrowSnapshot
|
|
296
|
+
}
|
|
297
|
+
]);
|
|
298
|
+
input.logger?.(`verified ${signature}: ${report.label} ${report.beforeUi} -> ${report.afterUi} (${report.deltaUi}); obligation borrow ${beforeBorrow.toString()} -> ${afterBorrow.toString()}`);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
async function prepareLiveMarinade(input) {
|
|
303
|
+
if (input.intent.protocol !== "marinade" || input.intent.action !== "stake") {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
if (!(0, env_1.isLiveMarinadeEnabled)()) {
|
|
307
|
+
input.logger?.("live marinade disabled via ENABLE_LIVE_MARINADE");
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
const rpcUrl = (0, env_1.getRpcUrl)();
|
|
311
|
+
const cluster = (0, env_1.detectClusterFromRpcUrl)(rpcUrl);
|
|
312
|
+
if (cluster !== "devnet" && cluster !== "unknown") {
|
|
313
|
+
input.logger?.(`live marinade staking currently intended for devnet; current cluster=${cluster}`);
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
const rpcClient = new RpcClient_1.RpcClient(rpcUrl, "confirmed");
|
|
317
|
+
const tokenService = new TokenService_1.TokenService(rpcClient);
|
|
318
|
+
const verifier = new PostTransactionVerifier_1.PostTransactionVerifier(rpcClient, tokenService);
|
|
319
|
+
const connection = new web3_js_1.Connection(rpcUrl, "confirmed");
|
|
320
|
+
const latestBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
321
|
+
const marinade = new marinade_ts_sdk_1.Marinade(new marinade_ts_sdk_1.MarinadeConfig({
|
|
322
|
+
connection,
|
|
323
|
+
publicKey: input.walletManager.publicKey
|
|
324
|
+
}));
|
|
325
|
+
const marinadeState = await marinade.getMarinadeState();
|
|
326
|
+
const msolSnapshot = await verifier.snapshotSplBalanceForOwner({
|
|
327
|
+
label: `Marinade mSOL balance (${marinadeState.mSolMintAddress.toBase58()})`,
|
|
328
|
+
mint: marinadeState.mSolMintAddress,
|
|
329
|
+
owner: input.walletManager.publicKey
|
|
330
|
+
});
|
|
331
|
+
const prepared = await marinade.deposit(new marinade_ts_sdk_1.BN(input.intent.amountLamports));
|
|
332
|
+
return {
|
|
333
|
+
confirmationStrategy: {
|
|
334
|
+
blockhash: latestBlockhash.blockhash,
|
|
335
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
336
|
+
signature: ""
|
|
337
|
+
},
|
|
338
|
+
protocol: input.intent.protocol,
|
|
339
|
+
policyConfigPatch: {
|
|
340
|
+
rules: {
|
|
341
|
+
allowOpaqueProgramIds: [marinade.config.marinadeFinanceProgramId.toBase58()],
|
|
342
|
+
allowedProgramIds: [marinade.config.marinadeFinanceProgramId.toBase58()]
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
toExecutionResult(signature) {
|
|
346
|
+
return {
|
|
347
|
+
action: input.intent.action,
|
|
348
|
+
memo: `LIVE:MARINADE:stake:${input.intent.amountLamports}`,
|
|
349
|
+
mock: false,
|
|
350
|
+
protocol: input.intent.protocol,
|
|
351
|
+
signature
|
|
352
|
+
};
|
|
353
|
+
},
|
|
354
|
+
transaction: await buildSignedVersionedTransaction({
|
|
355
|
+
instructions: prepared.transaction.instructions,
|
|
356
|
+
payer: input.walletManager.publicKey,
|
|
357
|
+
recentBlockhash: latestBlockhash.blockhash,
|
|
358
|
+
walletManager: input.walletManager
|
|
359
|
+
}),
|
|
360
|
+
async verifyExecution(signature) {
|
|
361
|
+
const [report] = await verifier.assertBalanceChanges([
|
|
362
|
+
{
|
|
363
|
+
minIncreaseRaw: 1n,
|
|
364
|
+
snapshot: msolSnapshot
|
|
365
|
+
}
|
|
366
|
+
]);
|
|
367
|
+
input.logger?.(`verified ${signature}: ${report.label} ${report.beforeUi} -> ${report.afterUi} (${report.deltaUi})`);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function buildVersionedTransaction(input) {
|
|
372
|
+
const message = new web3_js_1.TransactionMessage({
|
|
373
|
+
instructions: input.instructions,
|
|
374
|
+
payerKey: input.payer,
|
|
375
|
+
recentBlockhash: input.recentBlockhash
|
|
376
|
+
}).compileToV0Message();
|
|
377
|
+
return new web3_js_1.VersionedTransaction(message);
|
|
378
|
+
}
|
|
379
|
+
async function buildSignedVersionedTransaction(input) {
|
|
380
|
+
const transaction = buildVersionedTransaction(input);
|
|
381
|
+
return input.walletManager.signTransaction(transaction);
|
|
382
|
+
}
|
|
383
|
+
function buildKaminoInstructions(action, cluster, logger) {
|
|
384
|
+
const instructions = klend_sdk_1.KaminoAction.actionToIxs(action);
|
|
385
|
+
const labels = klend_sdk_1.KaminoAction.actionToIxLabels(action);
|
|
386
|
+
if (cluster !== "devnet") {
|
|
387
|
+
return instructions.map(kaminoInstructionCompat_1.convertKaminoInstruction);
|
|
388
|
+
}
|
|
389
|
+
const filtered = instructions.filter((_, index) => !labels[index]?.startsWith("RefreshReserve["));
|
|
390
|
+
if (filtered.length !== instructions.length) {
|
|
391
|
+
logger?.(`kamino devnet compatibility removed ${instructions.length - filtered.length} RefreshReserve instructions`);
|
|
392
|
+
}
|
|
393
|
+
return filtered.map(kaminoInstructionCompat_1.convertKaminoInstruction);
|
|
394
|
+
}
|