@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,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExecutionIdempotencyGuard = exports.BalanceService = exports.TokenService = exports.PostTransactionVerifier = exports.TransactionService = exports.WalletManager = exports.RpcFailoverClient = exports.RpcClient = void 0;
|
|
4
|
+
var RpcClient_1 = require("./rpc/RpcClient");
|
|
5
|
+
Object.defineProperty(exports, "RpcClient", { enumerable: true, get: function () { return RpcClient_1.RpcClient; } });
|
|
6
|
+
var RpcFailoverClient_1 = require("./rpc/RpcFailoverClient");
|
|
7
|
+
Object.defineProperty(exports, "RpcFailoverClient", { enumerable: true, get: function () { return RpcFailoverClient_1.RpcFailoverClient; } });
|
|
8
|
+
var WalletManager_1 = require("./wallet/WalletManager");
|
|
9
|
+
Object.defineProperty(exports, "WalletManager", { enumerable: true, get: function () { return WalletManager_1.WalletManager; } });
|
|
10
|
+
var TransactionService_1 = require("./transactions/TransactionService");
|
|
11
|
+
Object.defineProperty(exports, "TransactionService", { enumerable: true, get: function () { return TransactionService_1.TransactionService; } });
|
|
12
|
+
var PostTransactionVerifier_1 = require("./transactions/PostTransactionVerifier");
|
|
13
|
+
Object.defineProperty(exports, "PostTransactionVerifier", { enumerable: true, get: function () { return PostTransactionVerifier_1.PostTransactionVerifier; } });
|
|
14
|
+
var TokenService_1 = require("./tokens/TokenService");
|
|
15
|
+
Object.defineProperty(exports, "TokenService", { enumerable: true, get: function () { return TokenService_1.TokenService; } });
|
|
16
|
+
var BalanceService_1 = require("./balances/BalanceService");
|
|
17
|
+
Object.defineProperty(exports, "BalanceService", { enumerable: true, get: function () { return BalanceService_1.BalanceService; } });
|
|
18
|
+
var ExecutionIdempotencyGuard_1 = require("./idempotency/ExecutionIdempotencyGuard");
|
|
19
|
+
Object.defineProperty(exports, "ExecutionIdempotencyGuard", { enumerable: true, get: function () { return ExecutionIdempotencyGuard_1.ExecutionIdempotencyGuard; } });
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RpcClient = void 0;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const env_1 = require("../../config/env");
|
|
6
|
+
class RpcClient {
|
|
7
|
+
connection;
|
|
8
|
+
constructor(rpcUrl = (0, env_1.getRpcUrl)(), commitment = "confirmed") {
|
|
9
|
+
this.connection = new web3_js_1.Connection(rpcUrl, commitment);
|
|
10
|
+
}
|
|
11
|
+
get rpcUrl() {
|
|
12
|
+
return this.connection.rpcEndpoint;
|
|
13
|
+
}
|
|
14
|
+
async getLatestBlockhash(commitment = "confirmed") {
|
|
15
|
+
return this.connection.getLatestBlockhash(commitment);
|
|
16
|
+
}
|
|
17
|
+
async getBalance(publicKey, commitment = "confirmed") {
|
|
18
|
+
return this.connection.getBalance(publicKey, commitment);
|
|
19
|
+
}
|
|
20
|
+
async getTokenAccountBalance(publicKey, commitment = "confirmed") {
|
|
21
|
+
return this.connection.getTokenAccountBalance(publicKey, commitment);
|
|
22
|
+
}
|
|
23
|
+
async getAccountInfo(publicKey, commitment = "confirmed") {
|
|
24
|
+
return this.connection.getAccountInfo(publicKey, commitment);
|
|
25
|
+
}
|
|
26
|
+
async sendTransaction(transaction, options) {
|
|
27
|
+
return this.connection.sendTransaction(transaction, options);
|
|
28
|
+
}
|
|
29
|
+
async confirmTransaction(strategy, commitment = "confirmed") {
|
|
30
|
+
if (typeof strategy === "string") {
|
|
31
|
+
return this.connection.confirmTransaction(strategy, commitment);
|
|
32
|
+
}
|
|
33
|
+
return this.connection.confirmTransaction(strategy, commitment);
|
|
34
|
+
}
|
|
35
|
+
async simulateTransaction(transaction, options) {
|
|
36
|
+
return this.connection.simulateTransaction(transaction, {
|
|
37
|
+
commitment: options?.commitment ?? "confirmed",
|
|
38
|
+
sigVerify: options?.sigVerify ?? true
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async requestAirdrop(publicKey, lamports) {
|
|
42
|
+
return this.connection.requestAirdrop(publicKey, lamports);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.RpcClient = RpcClient;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RpcFailoverClient = void 0;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
6
|
+
const DEFAULT_BASE_DELAY_MS = 500;
|
|
7
|
+
const DEFAULT_MAX_DELAY_MS = 4000;
|
|
8
|
+
/**
|
|
9
|
+
* RPC client with automatic failover from primary to fallback URL,
|
|
10
|
+
* exponential backoff, and random jitter on retries.
|
|
11
|
+
*/
|
|
12
|
+
class RpcFailoverClient {
|
|
13
|
+
primaryConnection;
|
|
14
|
+
fallbackConnection;
|
|
15
|
+
maxRetries;
|
|
16
|
+
baseDelayMs;
|
|
17
|
+
maxDelayMs;
|
|
18
|
+
commitment;
|
|
19
|
+
primaryUrl;
|
|
20
|
+
fallbackUrl;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.commitment = config.commitment ?? "confirmed";
|
|
23
|
+
this.primaryUrl = config.primaryUrl;
|
|
24
|
+
this.fallbackUrl = config.fallbackUrl ?? null;
|
|
25
|
+
this.primaryConnection = new web3_js_1.Connection(config.primaryUrl, this.commitment);
|
|
26
|
+
this.fallbackConnection = config.fallbackUrl
|
|
27
|
+
? new web3_js_1.Connection(config.fallbackUrl, this.commitment)
|
|
28
|
+
: null;
|
|
29
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
30
|
+
this.baseDelayMs = config.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
|
|
31
|
+
this.maxDelayMs = config.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
|
|
32
|
+
}
|
|
33
|
+
get connection() {
|
|
34
|
+
return this.primaryConnection;
|
|
35
|
+
}
|
|
36
|
+
get rpcUrl() {
|
|
37
|
+
return this.primaryConnection.rpcEndpoint;
|
|
38
|
+
}
|
|
39
|
+
async getLatestBlockhash(commitment = "confirmed") {
|
|
40
|
+
return this.executeWithFailover((conn) => conn.getLatestBlockhash(commitment));
|
|
41
|
+
}
|
|
42
|
+
async getBalance(publicKey, commitment = "confirmed") {
|
|
43
|
+
return this.executeWithFailover((conn) => conn.getBalance(publicKey, commitment));
|
|
44
|
+
}
|
|
45
|
+
async getTokenAccountBalance(publicKey, commitment = "confirmed") {
|
|
46
|
+
return this.executeWithFailover((conn) => conn.getTokenAccountBalance(publicKey, commitment));
|
|
47
|
+
}
|
|
48
|
+
async getAccountInfo(publicKey, commitment = "confirmed") {
|
|
49
|
+
return this.executeWithFailover((conn) => conn.getAccountInfo(publicKey, commitment));
|
|
50
|
+
}
|
|
51
|
+
async sendTransaction(transaction, options) {
|
|
52
|
+
return this.executeWithFailover((conn) => conn.sendTransaction(transaction, options));
|
|
53
|
+
}
|
|
54
|
+
async confirmTransaction(strategy, commitment = "confirmed") {
|
|
55
|
+
return this.executeWithFailover((conn) => conn.confirmTransaction(strategy, commitment));
|
|
56
|
+
}
|
|
57
|
+
async simulateTransaction(transaction, options) {
|
|
58
|
+
return this.executeWithFailover((conn) => conn.simulateTransaction(transaction, {
|
|
59
|
+
commitment: options?.commitment ?? "confirmed",
|
|
60
|
+
sigVerify: options?.sigVerify ?? true
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
async requestAirdrop(publicKey, lamports) {
|
|
64
|
+
return this.executeWithFailover((conn) => conn.requestAirdrop(publicKey, lamports));
|
|
65
|
+
}
|
|
66
|
+
async executeWithFailover(operation) {
|
|
67
|
+
const connections = [this.primaryConnection];
|
|
68
|
+
if (this.fallbackConnection) {
|
|
69
|
+
connections.push(this.fallbackConnection);
|
|
70
|
+
}
|
|
71
|
+
let lastError = null;
|
|
72
|
+
for (const conn of connections) {
|
|
73
|
+
for (let attempt = 0; attempt < this.maxRetries; attempt += 1) {
|
|
74
|
+
try {
|
|
75
|
+
return await operation(conn);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
79
|
+
if (attempt < this.maxRetries - 1) {
|
|
80
|
+
await this.backoff(attempt);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw lastError ?? new Error("RPC failover exhausted all retries on all endpoints.");
|
|
86
|
+
}
|
|
87
|
+
async backoff(attempt) {
|
|
88
|
+
const exponentialDelay = this.baseDelayMs * Math.pow(2, attempt);
|
|
89
|
+
const cappedDelay = Math.min(exponentialDelay, this.maxDelayMs);
|
|
90
|
+
const jitter = Math.random() * cappedDelay * 0.3;
|
|
91
|
+
const totalDelay = cappedDelay + jitter;
|
|
92
|
+
await new Promise((resolve) => {
|
|
93
|
+
setTimeout(resolve, totalDelay);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.RpcFailoverClient = RpcFailoverClient;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TokenService = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const programs_1 = require("../../solana/programs");
|
|
7
|
+
class TokenService {
|
|
8
|
+
rpcClient;
|
|
9
|
+
constructor(rpcClient) {
|
|
10
|
+
this.rpcClient = rpcClient;
|
|
11
|
+
}
|
|
12
|
+
async getMintDecimals(mint) {
|
|
13
|
+
const mintInfo = await (0, spl_token_1.getMint)(this.rpcClient.connection, mint, "confirmed");
|
|
14
|
+
return mintInfo.decimals;
|
|
15
|
+
}
|
|
16
|
+
findAssociatedTokenAddress(owner, mint) {
|
|
17
|
+
return (0, spl_token_1.getAssociatedTokenAddressSync)(mint, owner, false, programs_1.TOKEN_PROGRAM_ID, programs_1.ASSOCIATED_TOKEN_PROGRAM_ID);
|
|
18
|
+
}
|
|
19
|
+
async ensureAtaInstruction(input) {
|
|
20
|
+
const address = this.findAssociatedTokenAddress(input.owner, input.mint);
|
|
21
|
+
const accountInfo = await this.rpcClient.getAccountInfo(address, "confirmed");
|
|
22
|
+
if (accountInfo) {
|
|
23
|
+
return {
|
|
24
|
+
address,
|
|
25
|
+
createInstruction: null
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
address,
|
|
30
|
+
createInstruction: (0, spl_token_1.createAssociatedTokenAccountInstruction)(input.payer, address, input.owner, input.mint, programs_1.TOKEN_PROGRAM_ID, programs_1.ASSOCIATED_TOKEN_PROGRAM_ID)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
buildWrapSolInstructions(input) {
|
|
34
|
+
if (!Number.isInteger(input.amountLamports) || input.amountLamports <= 0) {
|
|
35
|
+
throw new Error("Wrap SOL amount must be a positive integer lamport value.");
|
|
36
|
+
}
|
|
37
|
+
const associatedTokenAddress = this.findAssociatedTokenAddress(input.wallet.publicKey, programs_1.NATIVE_MINT);
|
|
38
|
+
const instructions = [];
|
|
39
|
+
if (input.createAtaIfMissing) {
|
|
40
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountInstruction)(input.wallet.publicKey, associatedTokenAddress, input.wallet.publicKey, programs_1.NATIVE_MINT, programs_1.TOKEN_PROGRAM_ID, programs_1.ASSOCIATED_TOKEN_PROGRAM_ID));
|
|
41
|
+
}
|
|
42
|
+
instructions.push(web3_js_1.SystemProgram.transfer({
|
|
43
|
+
fromPubkey: input.wallet.publicKey,
|
|
44
|
+
toPubkey: associatedTokenAddress,
|
|
45
|
+
lamports: input.amountLamports
|
|
46
|
+
}), (0, spl_token_1.createSyncNativeInstruction)(associatedTokenAddress, programs_1.TOKEN_PROGRAM_ID));
|
|
47
|
+
return {
|
|
48
|
+
associatedTokenAddress,
|
|
49
|
+
createdAssociatedTokenAccount: input.createAtaIfMissing,
|
|
50
|
+
instructions
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async buildCreateMintInstructions(input) {
|
|
54
|
+
const mintKeypair = web3_js_1.Keypair.generate();
|
|
55
|
+
const rent = await this.rpcClient.connection.getMinimumBalanceForRentExemption(82);
|
|
56
|
+
const instructions = [
|
|
57
|
+
web3_js_1.SystemProgram.createAccount({
|
|
58
|
+
fromPubkey: input.payer,
|
|
59
|
+
newAccountPubkey: mintKeypair.publicKey,
|
|
60
|
+
lamports: rent,
|
|
61
|
+
programId: programs_1.TOKEN_PROGRAM_ID,
|
|
62
|
+
space: 82
|
|
63
|
+
}),
|
|
64
|
+
(0, spl_token_1.createInitializeMint2Instruction)(mintKeypair.publicKey, input.decimals, input.mintAuthority, input.mintAuthority, programs_1.TOKEN_PROGRAM_ID)
|
|
65
|
+
];
|
|
66
|
+
return {
|
|
67
|
+
mintKeypair,
|
|
68
|
+
instructions
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
buildMintToInstruction(input) {
|
|
72
|
+
return (0, spl_token_1.createMintToInstruction)(input.mint, input.destinationAta, input.authority, input.amount, [], programs_1.TOKEN_PROGRAM_ID);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.TokenService = TokenService;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostTransactionVerifier = void 0;
|
|
4
|
+
const SOL_DECIMALS = 9;
|
|
5
|
+
class PostTransactionVerifier {
|
|
6
|
+
rpcClient;
|
|
7
|
+
tokenService;
|
|
8
|
+
constructor(rpcClient, tokenService) {
|
|
9
|
+
this.rpcClient = rpcClient;
|
|
10
|
+
this.tokenService = tokenService;
|
|
11
|
+
}
|
|
12
|
+
async snapshotSolBalance(owner, label = "SOL balance") {
|
|
13
|
+
const beforeLamports = await this.rpcClient.getBalance(owner, "confirmed");
|
|
14
|
+
return {
|
|
15
|
+
address: owner,
|
|
16
|
+
beforeRaw: BigInt(beforeLamports),
|
|
17
|
+
decimals: SOL_DECIMALS,
|
|
18
|
+
kind: "sol",
|
|
19
|
+
label
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async snapshotSplBalanceForOwner(input) {
|
|
23
|
+
const tokenAccount = this.tokenService.findAssociatedTokenAddress(input.owner, input.mint);
|
|
24
|
+
return this.snapshotSplTokenAccount({
|
|
25
|
+
label: input.label ?? `Token balance for ${input.mint.toBase58()}`,
|
|
26
|
+
mint: input.mint,
|
|
27
|
+
tokenAccount
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async snapshotSplTokenAccount(input) {
|
|
31
|
+
const decimals = await this.tokenService.getMintDecimals(input.mint);
|
|
32
|
+
const beforeRaw = await this.getSplTokenBalanceRaw(input.tokenAccount);
|
|
33
|
+
return {
|
|
34
|
+
address: input.tokenAccount,
|
|
35
|
+
beforeRaw,
|
|
36
|
+
decimals,
|
|
37
|
+
kind: "spl",
|
|
38
|
+
label: input.label ?? `Token account ${input.tokenAccount.toBase58()}`
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async assertBalanceChanges(expectations) {
|
|
42
|
+
const reports = await Promise.all(expectations.map(async (expectation) => this.buildReport(expectation)));
|
|
43
|
+
for (const [index, report] of reports.entries()) {
|
|
44
|
+
const expectation = expectations[index];
|
|
45
|
+
if (expectation.minIncreaseRaw !== undefined && report.deltaRaw < expectation.minIncreaseRaw) {
|
|
46
|
+
throw new Error(`${report.label} verification failed: expected increase >= ${expectation.minIncreaseRaw.toString()} raw, got ${report.deltaRaw.toString()} raw (${report.beforeUi} -> ${report.afterUi}).`);
|
|
47
|
+
}
|
|
48
|
+
if (expectation.maxDecreaseRaw !== undefined &&
|
|
49
|
+
report.deltaRaw < 0n &&
|
|
50
|
+
-report.deltaRaw > expectation.maxDecreaseRaw) {
|
|
51
|
+
throw new Error(`${report.label} verification failed: expected decrease <= ${expectation.maxDecreaseRaw.toString()} raw, got ${(-report.deltaRaw).toString()} raw (${report.beforeUi} -> ${report.afterUi}).`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return reports;
|
|
55
|
+
}
|
|
56
|
+
async buildReport(expectation) {
|
|
57
|
+
const afterRaw = await this.readCurrentRaw(expectation.snapshot);
|
|
58
|
+
const deltaRaw = afterRaw - expectation.snapshot.beforeRaw;
|
|
59
|
+
return {
|
|
60
|
+
address: expectation.snapshot.address.toBase58(),
|
|
61
|
+
afterRaw,
|
|
62
|
+
afterUi: formatRawAmount(afterRaw, expectation.snapshot.decimals),
|
|
63
|
+
beforeRaw: expectation.snapshot.beforeRaw,
|
|
64
|
+
beforeUi: formatRawAmount(expectation.snapshot.beforeRaw, expectation.snapshot.decimals),
|
|
65
|
+
deltaRaw,
|
|
66
|
+
deltaUi: formatSignedRawAmount(deltaRaw, expectation.snapshot.decimals),
|
|
67
|
+
kind: expectation.snapshot.kind,
|
|
68
|
+
label: expectation.label ?? expectation.snapshot.label
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async readCurrentRaw(snapshot) {
|
|
72
|
+
if (snapshot.kind === "sol") {
|
|
73
|
+
return BigInt(await this.rpcClient.getBalance(snapshot.address, "confirmed"));
|
|
74
|
+
}
|
|
75
|
+
return this.getSplTokenBalanceRaw(snapshot.address);
|
|
76
|
+
}
|
|
77
|
+
async getSplTokenBalanceRaw(tokenAccount) {
|
|
78
|
+
const account = await this.rpcClient.getAccountInfo(tokenAccount, "confirmed");
|
|
79
|
+
if (!account) {
|
|
80
|
+
return 0n;
|
|
81
|
+
}
|
|
82
|
+
const tokenBalance = await this.rpcClient.getTokenAccountBalance(tokenAccount, "confirmed");
|
|
83
|
+
return BigInt(tokenBalance.value.amount);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.PostTransactionVerifier = PostTransactionVerifier;
|
|
87
|
+
function formatSignedRawAmount(raw, decimals) {
|
|
88
|
+
const sign = raw < 0n ? "-" : "+";
|
|
89
|
+
const absolute = raw < 0n ? -raw : raw;
|
|
90
|
+
return `${sign}${formatRawAmount(absolute, decimals)}`;
|
|
91
|
+
}
|
|
92
|
+
function formatRawAmount(raw, decimals) {
|
|
93
|
+
const negative = raw < 0n;
|
|
94
|
+
const absolute = negative ? -raw : raw;
|
|
95
|
+
const divisor = 10n ** BigInt(decimals);
|
|
96
|
+
const whole = absolute / divisor;
|
|
97
|
+
const fraction = absolute % divisor;
|
|
98
|
+
if (fraction === 0n) {
|
|
99
|
+
return `${negative ? "-" : ""}${whole.toString()}`;
|
|
100
|
+
}
|
|
101
|
+
const fractionString = fraction.toString().padStart(decimals, "0").replace(/0+$/u, "");
|
|
102
|
+
return `${negative ? "-" : ""}${whole.toString()}.${fractionString}`;
|
|
103
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransactionService = void 0;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
6
|
+
const programs_1 = require("../../solana/programs");
|
|
7
|
+
const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
8
|
+
class TransactionService {
|
|
9
|
+
rpcClient;
|
|
10
|
+
constructor(rpcClient) {
|
|
11
|
+
this.rpcClient = rpcClient;
|
|
12
|
+
}
|
|
13
|
+
async buildTransaction(input) {
|
|
14
|
+
const latestBlockhash = await this.rpcClient.getLatestBlockhash("confirmed");
|
|
15
|
+
const message = new web3_js_1.TransactionMessage({
|
|
16
|
+
payerKey: input.feePayer,
|
|
17
|
+
recentBlockhash: latestBlockhash.blockhash,
|
|
18
|
+
instructions: input.instructions
|
|
19
|
+
}).compileToV0Message();
|
|
20
|
+
const transaction = new web3_js_1.VersionedTransaction(message);
|
|
21
|
+
const signedTransaction = await input.signer.signTransaction(transaction);
|
|
22
|
+
return {
|
|
23
|
+
confirmationStrategy: {
|
|
24
|
+
blockhash: latestBlockhash.blockhash,
|
|
25
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
26
|
+
signature: ""
|
|
27
|
+
},
|
|
28
|
+
instructionsCount: input.instructions.length,
|
|
29
|
+
transaction: signedTransaction
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
buildSolTransferInstruction(input) {
|
|
33
|
+
return web3_js_1.SystemProgram.transfer({
|
|
34
|
+
fromPubkey: input.from,
|
|
35
|
+
toPubkey: input.to,
|
|
36
|
+
lamports: input.lamports
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
buildSolTransferInstructionInSol(input) {
|
|
40
|
+
const lamports = Math.round(input.amountSol * LAMPORTS_PER_SOL);
|
|
41
|
+
return this.buildSolTransferInstruction({
|
|
42
|
+
from: input.from,
|
|
43
|
+
to: input.to,
|
|
44
|
+
lamports
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
buildSplTransferInstruction(input) {
|
|
48
|
+
return (0, spl_token_1.createTransferInstruction)(input.sourceAta, input.destinationAta, input.owner, input.amount, input.multiSigners, input.programId);
|
|
49
|
+
}
|
|
50
|
+
buildSplTransferCheckedInstruction(input) {
|
|
51
|
+
return (0, spl_token_1.createTransferCheckedInstruction)(input.sourceAta, input.mint, input.destinationAta, input.owner, input.amount, input.decimals, input.multiSigners, input.programId);
|
|
52
|
+
}
|
|
53
|
+
buildMemoInstruction(memo) {
|
|
54
|
+
return new web3_js_1.TransactionInstruction({
|
|
55
|
+
programId: programs_1.MEMO_PROGRAM_ID,
|
|
56
|
+
keys: [],
|
|
57
|
+
data: Buffer.from(memo, "utf8")
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async simulate(transaction) {
|
|
61
|
+
const simulation = await this.rpcClient.simulateTransaction(transaction, {
|
|
62
|
+
commitment: "confirmed",
|
|
63
|
+
sigVerify: true
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
err: simulation.value.err,
|
|
67
|
+
logs: simulation.value.logs ?? null,
|
|
68
|
+
unitsConsumed: simulation.value.unitsConsumed ?? null
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async sendAndConfirm(input) {
|
|
72
|
+
const sendable = this.normalizeSendable(input);
|
|
73
|
+
const signature = await this.rpcClient.sendTransaction(sendable.transaction, {
|
|
74
|
+
maxRetries: 3,
|
|
75
|
+
preflightCommitment: "confirmed"
|
|
76
|
+
});
|
|
77
|
+
const confirmation = await this.rpcClient.confirmTransaction(this.resolveConfirmationTarget(sendable.confirmationStrategy, signature), "confirmed");
|
|
78
|
+
return {
|
|
79
|
+
signature,
|
|
80
|
+
slot: confirmation.context.slot
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
normalizeSendable(input) {
|
|
84
|
+
if (input instanceof web3_js_1.VersionedTransaction) {
|
|
85
|
+
return {
|
|
86
|
+
transaction: input
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return input;
|
|
90
|
+
}
|
|
91
|
+
resolveConfirmationTarget(confirmationStrategy, signature) {
|
|
92
|
+
if (!confirmationStrategy) {
|
|
93
|
+
return signature;
|
|
94
|
+
}
|
|
95
|
+
if (typeof confirmationStrategy === "string") {
|
|
96
|
+
return confirmationStrategy;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
...confirmationStrategy,
|
|
100
|
+
signature
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.TransactionService = TransactionService;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WalletManager = void 0;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const env_1 = require("../../config/env");
|
|
6
|
+
class LocalTransactionSigner {
|
|
7
|
+
keypair;
|
|
8
|
+
source;
|
|
9
|
+
constructor(keypair, source) {
|
|
10
|
+
this.keypair = keypair;
|
|
11
|
+
this.source = source;
|
|
12
|
+
}
|
|
13
|
+
get publicKey() {
|
|
14
|
+
return this.keypair.publicKey;
|
|
15
|
+
}
|
|
16
|
+
async signTransaction(transaction) {
|
|
17
|
+
transaction.sign([this.keypair]);
|
|
18
|
+
return transaction;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class RemoteTransactionSigner {
|
|
22
|
+
publicKey;
|
|
23
|
+
bearerToken;
|
|
24
|
+
url;
|
|
25
|
+
source = "remote";
|
|
26
|
+
constructor(publicKey, bearerToken, url) {
|
|
27
|
+
this.publicKey = publicKey;
|
|
28
|
+
this.bearerToken = bearerToken;
|
|
29
|
+
this.url = url;
|
|
30
|
+
}
|
|
31
|
+
async signTransaction(transaction) {
|
|
32
|
+
const response = await fetch(this.url, {
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
publicKey: this.publicKey.toBase58(),
|
|
35
|
+
transactionBase64: Buffer.from(transaction.serialize()).toString("base64")
|
|
36
|
+
}),
|
|
37
|
+
headers: {
|
|
38
|
+
Authorization: `Bearer ${this.bearerToken}`,
|
|
39
|
+
"Content-Type": "application/json"
|
|
40
|
+
},
|
|
41
|
+
method: "POST"
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const message = await response.text();
|
|
45
|
+
throw new Error(`Remote signer request failed (${response.status} ${response.statusText}): ${message || "no response body"}`);
|
|
46
|
+
}
|
|
47
|
+
const payload = (await response.json());
|
|
48
|
+
const signedTransactionBase64 = payload.signedTransactionBase64 ?? payload.transactionBase64 ?? null;
|
|
49
|
+
if (!signedTransactionBase64) {
|
|
50
|
+
throw new Error("Remote signer response did not include signedTransactionBase64.");
|
|
51
|
+
}
|
|
52
|
+
return web3_js_1.VersionedTransaction.deserialize(Buffer.from(signedTransactionBase64, "base64"));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
class WalletManager {
|
|
56
|
+
signer;
|
|
57
|
+
constructor(signer) {
|
|
58
|
+
this.signer = signer;
|
|
59
|
+
}
|
|
60
|
+
static generate() {
|
|
61
|
+
return new WalletManager(new LocalTransactionSigner(web3_js_1.Keypair.generate(), "generated"));
|
|
62
|
+
}
|
|
63
|
+
static loadFromEnv() {
|
|
64
|
+
const secretKey = (0, env_1.getOptionalSecretKey)();
|
|
65
|
+
if (!secretKey) {
|
|
66
|
+
throw new Error("AGENT_PRIVATE_KEY is not configured.");
|
|
67
|
+
}
|
|
68
|
+
return new WalletManager(new LocalTransactionSigner(web3_js_1.Keypair.fromSecretKey(secretKey), "env"));
|
|
69
|
+
}
|
|
70
|
+
static loadRemoteSigner() {
|
|
71
|
+
const remoteSigner = (0, env_1.getRemoteSignerConfig)();
|
|
72
|
+
if (!remoteSigner) {
|
|
73
|
+
throw new Error("Remote signer is not configured.");
|
|
74
|
+
}
|
|
75
|
+
return new WalletManager(new RemoteTransactionSigner(remoteSigner.publicKey, remoteSigner.bearerToken, remoteSigner.url));
|
|
76
|
+
}
|
|
77
|
+
static loadConfigured() {
|
|
78
|
+
const remoteSigner = (0, env_1.getRemoteSignerConfig)();
|
|
79
|
+
if (remoteSigner) {
|
|
80
|
+
return new WalletManager(new RemoteTransactionSigner(remoteSigner.publicKey, remoteSigner.bearerToken, remoteSigner.url));
|
|
81
|
+
}
|
|
82
|
+
return WalletManager.loadFromEnv();
|
|
83
|
+
}
|
|
84
|
+
static loadOrGenerate() {
|
|
85
|
+
const remoteSigner = (0, env_1.getRemoteSignerConfig)();
|
|
86
|
+
if (remoteSigner) {
|
|
87
|
+
return new WalletManager(new RemoteTransactionSigner(remoteSigner.publicKey, remoteSigner.bearerToken, remoteSigner.url));
|
|
88
|
+
}
|
|
89
|
+
const secretKey = (0, env_1.getOptionalSecretKey)();
|
|
90
|
+
if (!secretKey) {
|
|
91
|
+
return WalletManager.generate();
|
|
92
|
+
}
|
|
93
|
+
return new WalletManager(new LocalTransactionSigner(web3_js_1.Keypair.fromSecretKey(secretKey), "env"));
|
|
94
|
+
}
|
|
95
|
+
static fromSecretKey(secretKey, source = "env") {
|
|
96
|
+
return new WalletManager(new LocalTransactionSigner(web3_js_1.Keypair.fromSecretKey(secretKey), source));
|
|
97
|
+
}
|
|
98
|
+
get payer() {
|
|
99
|
+
if (!(this.signer instanceof LocalTransactionSigner)) {
|
|
100
|
+
throw new Error("This wallet uses a remote signer and does not expose a local keypair.");
|
|
101
|
+
}
|
|
102
|
+
return this.signer.keypair;
|
|
103
|
+
}
|
|
104
|
+
get publicKey() {
|
|
105
|
+
return this.signer.publicKey;
|
|
106
|
+
}
|
|
107
|
+
get source() {
|
|
108
|
+
return this.signer.source;
|
|
109
|
+
}
|
|
110
|
+
async signTransaction(transaction) {
|
|
111
|
+
return this.signer.signTransaction(transaction);
|
|
112
|
+
}
|
|
113
|
+
toSafeSummary() {
|
|
114
|
+
return {
|
|
115
|
+
publicKey: this.publicKey.toBase58(),
|
|
116
|
+
source: this.source
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.WalletManager = WalletManager;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeFiCoordinator = void 0;
|
|
4
|
+
const policyFactory_1 = require("../agent/policyFactory");
|
|
5
|
+
const DeFiExecutor_1 = require("./DeFiExecutor");
|
|
6
|
+
const KaminoAdapter_1 = require("./adapters/KaminoAdapter");
|
|
7
|
+
const JupiterAdapter_1 = require("./adapters/JupiterAdapter");
|
|
8
|
+
const MarinadeAdapter_1 = require("./adapters/MarinadeAdapter");
|
|
9
|
+
const RaydiumAdapter_1 = require("./adapters/RaydiumAdapter");
|
|
10
|
+
const protocols_1 = require("./protocols");
|
|
11
|
+
class DeFiCoordinator {
|
|
12
|
+
walletManager;
|
|
13
|
+
koraSigner;
|
|
14
|
+
logger;
|
|
15
|
+
policy;
|
|
16
|
+
kaminoAdapter = new KaminoAdapter_1.KaminoAdapter();
|
|
17
|
+
jupiterAdapter = new JupiterAdapter_1.JupiterAdapter();
|
|
18
|
+
marinadeAdapter = new MarinadeAdapter_1.MarinadeAdapter();
|
|
19
|
+
raydiumAdapter = new RaydiumAdapter_1.RaydiumAdapter();
|
|
20
|
+
constructor(walletManager, koraSigner, logger = () => undefined, policy = (0, policyFactory_1.createDefaultAgentPolicy)({
|
|
21
|
+
maxSpend: {
|
|
22
|
+
lamports: 2_000_000
|
|
23
|
+
}
|
|
24
|
+
})) {
|
|
25
|
+
this.walletManager = walletManager;
|
|
26
|
+
this.koraSigner = koraSigner;
|
|
27
|
+
this.logger = logger;
|
|
28
|
+
this.policy = policy;
|
|
29
|
+
}
|
|
30
|
+
async runStakingStrategy(snapshot) {
|
|
31
|
+
const intent = this.marinadeAdapter.buildStakeIntent(snapshot);
|
|
32
|
+
if (!intent) {
|
|
33
|
+
this.logger("Staking strategy -> HOLD (Marinade adapter found insufficient idle SOL).");
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return this.execute(intent);
|
|
37
|
+
}
|
|
38
|
+
async runLiquidityStrategy(snapshot) {
|
|
39
|
+
const intent = this.raydiumAdapter.buildAddLiquidityIntent(snapshot);
|
|
40
|
+
if (!intent) {
|
|
41
|
+
this.logger("LP strategy -> HOLD (Raydium adapter found pool pricing out of range).");
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return this.execute(intent);
|
|
45
|
+
}
|
|
46
|
+
async runLendingStrategy(snapshot) {
|
|
47
|
+
const intent = this.kaminoAdapter.buildDepositIntent(snapshot);
|
|
48
|
+
if (!intent) {
|
|
49
|
+
this.logger("Lending strategy -> HOLD (Kamino adapter found insufficient idle USDC).");
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return this.execute(intent);
|
|
53
|
+
}
|
|
54
|
+
async runBorrowingStrategy(snapshot) {
|
|
55
|
+
const intent = this.kaminoAdapter.buildBorrowIntent(snapshot);
|
|
56
|
+
if (!intent) {
|
|
57
|
+
this.logger("Borrowing strategy -> HOLD (Kamino adapter found insufficient collateral or borrow demand).");
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return this.execute(intent);
|
|
61
|
+
}
|
|
62
|
+
async runTradeStrategy(snapshot) {
|
|
63
|
+
const intent = this.jupiterAdapter.buildTradeIntent(snapshot);
|
|
64
|
+
if (!intent) {
|
|
65
|
+
this.logger("Trade strategy -> HOLD (Jupiter adapter found no favorable setup).");
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return this.execute(intent);
|
|
69
|
+
}
|
|
70
|
+
async runFullSuite(snapshot) {
|
|
71
|
+
const results = await Promise.all([
|
|
72
|
+
this.runTradeStrategy(snapshot),
|
|
73
|
+
this.runStakingStrategy(snapshot),
|
|
74
|
+
this.runLiquidityStrategy(snapshot),
|
|
75
|
+
this.runLendingStrategy(snapshot),
|
|
76
|
+
this.runBorrowingStrategy(snapshot)
|
|
77
|
+
]);
|
|
78
|
+
return results.filter((result) => result !== null);
|
|
79
|
+
}
|
|
80
|
+
async execute(intent) {
|
|
81
|
+
const preset = protocols_1.PROTOCOL_PRESETS[intent.protocol];
|
|
82
|
+
this.logger(`${preset.label} strategy -> Policy Check -> Gasless Execution (${intent.action} on ${intent.marketId}).`);
|
|
83
|
+
const executor = new DeFiExecutor_1.DeFiExecutor(this.policy);
|
|
84
|
+
const result = await executor.executeIntent({
|
|
85
|
+
intent,
|
|
86
|
+
koraSigner: this.koraSigner,
|
|
87
|
+
walletManager: this.walletManager
|
|
88
|
+
});
|
|
89
|
+
this.logger(`${preset.label} strategy -> Executed ${result.mock ? "mock " : ""}${result.action} ${result.signature}`);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.DeFiCoordinator = DeFiCoordinator;
|