@gvnrdao/dh-sdk 0.0.1
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/README.md +77 -0
- package/dist/browser.d.ts +14 -0
- package/dist/browser.js +36 -0
- package/dist/constants/chunks/contract-abis.d.ts +6 -0
- package/dist/constants/chunks/contract-abis.js +39 -0
- package/dist/constants/chunks/environment.browser.d.ts +40 -0
- package/dist/constants/chunks/environment.browser.js +111 -0
- package/dist/constants/chunks/environment.d.ts +40 -0
- package/dist/constants/chunks/environment.js +146 -0
- package/dist/constants/chunks/sdk-config.d.ts +27 -0
- package/dist/constants/chunks/sdk-config.js +34 -0
- package/dist/constants/index.d.ts +9 -0
- package/dist/constants/index.js +28 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +50 -0
- package/dist/interfaces/chunks/IBTCProof.d.ts +32 -0
- package/dist/interfaces/chunks/IBTCProof.js +2 -0
- package/dist/interfaces/chunks/SDKTypes.d.ts +2 -0
- package/dist/interfaces/chunks/SDKTypes.js +19 -0
- package/dist/interfaces/chunks/btc.i.d.ts +36 -0
- package/dist/interfaces/chunks/btc.i.js +5 -0
- package/dist/interfaces/chunks/config.i.d.ts +45 -0
- package/dist/interfaces/chunks/config.i.js +5 -0
- package/dist/interfaces/chunks/contract-interactions.i.d.ts +66 -0
- package/dist/interfaces/chunks/contract-interactions.i.js +5 -0
- package/dist/interfaces/chunks/lit-actions.d.ts +27 -0
- package/dist/interfaces/chunks/lit-actions.i.d.ts +44 -0
- package/dist/interfaces/chunks/lit-actions.i.js +5 -0
- package/dist/interfaces/chunks/lit-actions.js +2 -0
- package/dist/interfaces/chunks/loan-operations.d.ts +56 -0
- package/dist/interfaces/chunks/loan-operations.i.d.ts +85 -0
- package/dist/interfaces/chunks/loan-operations.i.js +5 -0
- package/dist/interfaces/chunks/loan-operations.js +2 -0
- package/dist/interfaces/chunks/pkp-integration.i.d.ts +88 -0
- package/dist/interfaces/chunks/pkp-integration.i.js +5 -0
- package/dist/interfaces/chunks/requests.i.d.ts +28 -0
- package/dist/interfaces/chunks/requests.i.js +5 -0
- package/dist/interfaces/chunks/ucd-minting.i.d.ts +34 -0
- package/dist/interfaces/chunks/ucd-minting.i.js +5 -0
- package/dist/interfaces/chunks/utility.i.d.ts +64 -0
- package/dist/interfaces/chunks/utility.i.js +5 -0
- package/dist/interfaces/index.d.ts +15 -0
- package/dist/interfaces/index.js +40 -0
- package/dist/modules/contract-interaction-manager.module.d.ts +86 -0
- package/dist/modules/contract-interaction-manager.module.js +136 -0
- package/dist/modules/diamond-hands-sdk.module.d.ts +109 -0
- package/dist/modules/diamond-hands-sdk.module.js +773 -0
- package/dist/modules/loan-operations-manager.module.d.ts +92 -0
- package/dist/modules/loan-operations-manager.module.js +171 -0
- package/dist/modules/pkp-integration-manager.module.d.ts +86 -0
- package/dist/modules/pkp-integration-manager.module.js +62 -0
- package/dist/types/loanStatus.d.ts +10 -0
- package/dist/types/loanStatus.js +16 -0
- package/dist/utils/chunks/bitcoin-utils.d.ts +51 -0
- package/dist/utils/chunks/bitcoin-utils.js +135 -0
- package/dist/utils/chunks/environment-utils.d.ts +11 -0
- package/dist/utils/chunks/environment-utils.js +21 -0
- package/dist/utils/chunks/pkp-utils.d.ts +19 -0
- package/dist/utils/chunks/pkp-utils.js +44 -0
- package/dist/utils/chunks/validation-utils.d.ts +30 -0
- package/dist/utils/chunks/validation-utils.js +58 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.js +39 -0
- package/package.json +74 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DiamondHandsSDK = void 0;
|
|
4
|
+
const dh_lit_ops_1 = require("@gvnrdao/dh-lit-ops");
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
// Position Manager ABI for smart contract interaction
|
|
8
|
+
const POSITION_MANAGER_ABI = [
|
|
9
|
+
"function createPosition(bytes32 pkpId, uint256 amount, uint256 requestedCollateralRatio, uint256 selectedTerm, bytes calldata validatorSignature) external returns (bool)",
|
|
10
|
+
"function calculateCollateralRatio(bytes32 positionId) external view returns (uint256)",
|
|
11
|
+
"function getPositionDetails(bytes32 positionId) external view returns (tuple(bytes32 positionId, bytes32 pkpId, address borrower, uint256 btcAmount, uint256 ucdDebt, uint256 createdAt, uint256 lastUpdated, bool isActive, uint256 collateralRatio, uint256 requestedCollateralRatio, uint256 selectedTerm))",
|
|
12
|
+
"function getUserPositions(address user) external view returns (bytes32[] memory)",
|
|
13
|
+
"function getPositionByPKP(bytes32 pkpId) external view returns (bytes32)",
|
|
14
|
+
"function getPKPPositionData(bytes32 pkpId) external view returns (tuple(bytes32 positionId, address borrower, uint256 amount, uint256 requestedCollateralRatio, uint256 selectedTerm, uint256 createdAt, bool isActive))",
|
|
15
|
+
"function getPKPLoanParams(bytes32 pkpId) external view returns (uint256 amount, uint256 requestedCollateralRatio, uint256 selectedTerm)",
|
|
16
|
+
"event PositionCreated(bytes32 indexed positionId, bytes32 indexed pkpId, address indexed borrower, uint256 amount, uint256 requestedCollateralRatio, uint256 selectedTerm)",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Core Diamond Hands SDK Module
|
|
20
|
+
*
|
|
21
|
+
* This is the main SDK class that provides a high-level interface for Diamond Hands Protocol operations.
|
|
22
|
+
* It supports two operation modes:
|
|
23
|
+
* - Standalone: User provides signer and network, SDK creates PKPs directly via LIT Protocol
|
|
24
|
+
* - Service: SDK calls lit-ops-server backend which handles LIT Protocol operations
|
|
25
|
+
*
|
|
26
|
+
* Default behavior (if mode not specified):
|
|
27
|
+
* - Mode: "service"
|
|
28
|
+
* - Service endpoint: "http://localhost:3001"
|
|
29
|
+
*/
|
|
30
|
+
class DiamondHandsSDK {
|
|
31
|
+
constructor(config) {
|
|
32
|
+
this.litOps = null;
|
|
33
|
+
this.initialized = false;
|
|
34
|
+
this.config = config;
|
|
35
|
+
// Apply smart defaults
|
|
36
|
+
this.mode = config.mode || "service"; // Default to service mode
|
|
37
|
+
this.serviceEndpoint = config.serviceEndpoint || "http://localhost:3001"; // Default to localhost
|
|
38
|
+
// In service mode, use contractSigner's provider if available, otherwise create from ethRpcUrl
|
|
39
|
+
if (config.ethRpcUrl) {
|
|
40
|
+
this.provider = new ethers_1.ethers.providers.JsonRpcProvider(config.ethRpcUrl);
|
|
41
|
+
}
|
|
42
|
+
else if (config.contractSigner &&
|
|
43
|
+
"provider" in config.contractSigner &&
|
|
44
|
+
config.contractSigner.provider) {
|
|
45
|
+
// Use MetaMask's provider for blockchain interactions
|
|
46
|
+
this.provider = config.contractSigner
|
|
47
|
+
.provider;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Fallback: will be set later when contractSigner is available
|
|
51
|
+
this.provider = null;
|
|
52
|
+
}
|
|
53
|
+
// Validate configuration based on mode
|
|
54
|
+
this.validateConfig();
|
|
55
|
+
if (this.config.debug) {
|
|
56
|
+
console.log("๐๏ธ Diamond Hands SDK initialized with config:");
|
|
57
|
+
console.log(` Mode: ${this.mode}`);
|
|
58
|
+
if (this.mode === "standalone") {
|
|
59
|
+
console.log(` Network: ${config.litNetwork}`);
|
|
60
|
+
console.log(` LIT-Ops Signer: ${config.litOpsSigner?.address}`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.log(` Service Endpoint: ${this.serviceEndpoint}`);
|
|
64
|
+
}
|
|
65
|
+
console.log(` Contract: ${config.contractAddresses.positionManager}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Validate configuration based on the selected mode
|
|
70
|
+
*/
|
|
71
|
+
validateConfig() {
|
|
72
|
+
if (this.mode === "standalone") {
|
|
73
|
+
if (!this.config.litOpsSigner) {
|
|
74
|
+
throw new Error("litOpsSigner is required for standalone mode");
|
|
75
|
+
}
|
|
76
|
+
if (!this.config.litNetwork) {
|
|
77
|
+
throw new Error("litNetwork is required for standalone mode");
|
|
78
|
+
}
|
|
79
|
+
if (!this.config.ethRpcUrl) {
|
|
80
|
+
throw new Error("ethRpcUrl is required for standalone mode");
|
|
81
|
+
}
|
|
82
|
+
if (this.config.serviceEndpoint) {
|
|
83
|
+
throw new Error("serviceEndpoint must not be provided for standalone mode");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (this.mode === "service") {
|
|
87
|
+
if (this.config.litOpsSigner) {
|
|
88
|
+
throw new Error("litOpsSigner must not be provided for service mode");
|
|
89
|
+
}
|
|
90
|
+
if (this.config.litNetwork) {
|
|
91
|
+
throw new Error("litNetwork must not be provided for service mode (determined by serviceEndpoint)");
|
|
92
|
+
}
|
|
93
|
+
// In service mode, either ethRpcUrl or contractSigner with provider is required
|
|
94
|
+
if (!this.config.ethRpcUrl && !this.config.contractSigner) {
|
|
95
|
+
throw new Error("Service mode requires either ethRpcUrl or contractSigner for blockchain operations");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Initialize the SDK with required dependencies
|
|
101
|
+
*/
|
|
102
|
+
async initialize() {
|
|
103
|
+
if (this.initialized)
|
|
104
|
+
return;
|
|
105
|
+
try {
|
|
106
|
+
if (this.config.debug) {
|
|
107
|
+
console.log("๐ Initializing Diamond Hands SDK...");
|
|
108
|
+
console.log(` Mode: ${this.mode}`);
|
|
109
|
+
}
|
|
110
|
+
// Initialize LitOps only for standalone mode
|
|
111
|
+
if (this.mode === "standalone") {
|
|
112
|
+
if (this.config.debug) {
|
|
113
|
+
console.log("๐ง Initializing LitOps for standalone mode");
|
|
114
|
+
}
|
|
115
|
+
// LitOps will be initialized with signer during operations
|
|
116
|
+
// to support different signers for different operations
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
if (this.config.debug) {
|
|
120
|
+
console.log(`๐ Service mode - using endpoint: ${this.serviceEndpoint}`);
|
|
121
|
+
}
|
|
122
|
+
// Service mode - no LitOps initialization needed
|
|
123
|
+
}
|
|
124
|
+
this.initialized = true;
|
|
125
|
+
if (this.config.debug) {
|
|
126
|
+
console.log("โ
Diamond Hands SDK initialized successfully");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
throw new Error(`SDK initialization failed: ${error instanceof Error ? error.message : error}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Create a new Diamond Hands loan by:
|
|
135
|
+
* 1. Creating and validating a PKP (via standalone LitOps or service endpoint)
|
|
136
|
+
* 2. Extracting the validator signature from PKP creation result
|
|
137
|
+
* 3. Funding the contract wallet if needed
|
|
138
|
+
* 4. Calling the smart contract createPosition method with PKP validator signature
|
|
139
|
+
*/
|
|
140
|
+
async createLoan(request) {
|
|
141
|
+
this.ensureInitialized();
|
|
142
|
+
try {
|
|
143
|
+
if (this.config.debug) {
|
|
144
|
+
console.log("๐ฆ Starting Diamond Hands loan creation");
|
|
145
|
+
console.log(` Mode: ${this.mode}`);
|
|
146
|
+
console.log(` Collateral Amount: ${request.collateralAmount}`);
|
|
147
|
+
console.log(` Collateral Ratio: ${request.collateralRatio}%`);
|
|
148
|
+
console.log(` Selected Term: ${request.selectedTerm} months`);
|
|
149
|
+
}
|
|
150
|
+
// Step 1: Create PKP using the appropriate mode
|
|
151
|
+
let pkpResult;
|
|
152
|
+
if (this.mode === "standalone") {
|
|
153
|
+
pkpResult = await this.createLoanStandalone(request);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
pkpResult = await this.createLoanService(request);
|
|
157
|
+
}
|
|
158
|
+
return pkpResult;
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
162
|
+
if (this.config.debug) {
|
|
163
|
+
console.error("โ Loan creation failed:", errorMessage);
|
|
164
|
+
console.error("Full error:", error);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
success: false,
|
|
168
|
+
error: `Loan creation failed: ${errorMessage}`,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Create loan in standalone mode - uses LitOps directly
|
|
174
|
+
*/
|
|
175
|
+
async createLoanStandalone(request) {
|
|
176
|
+
if (this.config.debug) {
|
|
177
|
+
console.log("๐ง Standalone mode: Creating loan with LitOps");
|
|
178
|
+
console.log(` Network: ${this.config.litNetwork}`);
|
|
179
|
+
}
|
|
180
|
+
// Create dual-wallet setup (matching the working contract integration test)
|
|
181
|
+
// A) LIT-Ops wallet: Use the configured litOpsSigner with Yellowstone provider
|
|
182
|
+
if (!this.config.litOpsSigner) {
|
|
183
|
+
throw new Error("litOpsSigner is required in DiamondHandsSDKConfig for standalone mode");
|
|
184
|
+
}
|
|
185
|
+
const litProviderV5 = new ethers_1.ethers.providers.JsonRpcProvider("https://yellowstone-rpc.litprotocol.com");
|
|
186
|
+
const litOpsWallet = this.config.litOpsSigner.connect(litProviderV5);
|
|
187
|
+
// Setup contract wallet
|
|
188
|
+
const contractWallet = await this.setupContractWallet();
|
|
189
|
+
if (this.config.debug) {
|
|
190
|
+
console.log("๐ง Dual-wallet setup:");
|
|
191
|
+
console.log(` LIT-Ops wallet: ${litOpsWallet.address} (Yellowstone RPC)`);
|
|
192
|
+
const contractAddress = await contractWallet.getAddress();
|
|
193
|
+
console.log(` Contract wallet: ${contractAddress} (Local RPC)`);
|
|
194
|
+
console.log(` Wallets match: ${litOpsWallet.address === contractAddress}`);
|
|
195
|
+
}
|
|
196
|
+
// Initialize LitOps with the LIT-specific wallet
|
|
197
|
+
if (!this.litOps) {
|
|
198
|
+
this.litOps = new dh_lit_ops_1.LitOps({
|
|
199
|
+
mode: "standalone",
|
|
200
|
+
network: this.config.litNetwork || "datil-test",
|
|
201
|
+
signer: litOpsWallet, // Use LIT-Ops wallet with Yellowstone provider
|
|
202
|
+
debug: this.config.debug,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
// Step 1: Create and validate PKP using lit-ops production method
|
|
206
|
+
if (this.config.debug) {
|
|
207
|
+
console.log("๐ Step 1: Creating PKP via LIT-Ops getNewDiamondHandsLoanPkp");
|
|
208
|
+
}
|
|
209
|
+
let pkpResult = await this.createPKPWithRetry(litOpsWallet);
|
|
210
|
+
if (!pkpResult.success) {
|
|
211
|
+
throw new Error(`PKP creation failed: ${pkpResult.error}`);
|
|
212
|
+
}
|
|
213
|
+
return this.processLoanCreation(pkpResult, contractWallet, request);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create loan in service mode - calls lit-ops-server
|
|
217
|
+
*/
|
|
218
|
+
async createLoanService(request) {
|
|
219
|
+
if (this.config.debug) {
|
|
220
|
+
console.log("๐ Service mode: Creating loan via lit-ops-server");
|
|
221
|
+
console.log(` Service endpoint: ${this.serviceEndpoint}`);
|
|
222
|
+
}
|
|
223
|
+
// Step 1: Call service endpoint to create PKP
|
|
224
|
+
if (this.config.debug) {
|
|
225
|
+
console.log("๐ Step 1: Creating PKP via service endpoint");
|
|
226
|
+
}
|
|
227
|
+
const response = await fetch(`${this.serviceEndpoint}/api/lit/pkp/create-diamond-hands-loan`, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: {
|
|
230
|
+
"Content-Type": "application/json",
|
|
231
|
+
},
|
|
232
|
+
body: JSON.stringify({}), // Empty body, service handles PKP creation
|
|
233
|
+
});
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
throw new Error(`Service call failed: ${response.status} ${response.statusText}`);
|
|
236
|
+
}
|
|
237
|
+
const pkpResult = await response.json();
|
|
238
|
+
if (!pkpResult.success) {
|
|
239
|
+
throw new Error(`Service PKP creation failed: ${pkpResult.error || "Unknown error"}`);
|
|
240
|
+
}
|
|
241
|
+
if (this.config.debug) {
|
|
242
|
+
console.log("โ
Service PKP creation successful");
|
|
243
|
+
console.log(` Token ID: ${pkpResult.pkpData?.tokenId}`);
|
|
244
|
+
console.log(` ETH Address: ${pkpResult.pkpData?.ethAddress}`);
|
|
245
|
+
}
|
|
246
|
+
// Setup contract wallet for local operations
|
|
247
|
+
const contractWallet = await this.setupContractWallet();
|
|
248
|
+
// Convert service response to expected format
|
|
249
|
+
const formattedPkpResult = {
|
|
250
|
+
success: true,
|
|
251
|
+
pkpData: {
|
|
252
|
+
tokenId: pkpResult.pkpData?.tokenId,
|
|
253
|
+
ethAddress: pkpResult.pkpData?.ethAddress,
|
|
254
|
+
publicKey: pkpResult.pkpData?.publicKey,
|
|
255
|
+
validationSignature: pkpResult.validationResult?.signature,
|
|
256
|
+
// Include Bitcoin addresses if available
|
|
257
|
+
btcAddresses: pkpResult.pkpData?.btcAddresses,
|
|
258
|
+
},
|
|
259
|
+
auditTrail: {
|
|
260
|
+
steps: pkpResult.auditTrail?.steps || [],
|
|
261
|
+
},
|
|
262
|
+
// Include validation results
|
|
263
|
+
validationResult: pkpResult.validationResult,
|
|
264
|
+
};
|
|
265
|
+
return this.processLoanCreation(formattedPkpResult, contractWallet, request, true);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Setup contract wallet for Ethereum transactions
|
|
269
|
+
*/
|
|
270
|
+
async setupContractWallet() {
|
|
271
|
+
if (!this.config.contractSigner) {
|
|
272
|
+
throw new Error("contractSigner is required in DiamondHandsSDKConfig for contract operations");
|
|
273
|
+
}
|
|
274
|
+
let contractWallet;
|
|
275
|
+
if ("privateKey" in this.config.contractSigner &&
|
|
276
|
+
this.config.contractSigner.privateKey) {
|
|
277
|
+
// If signer is a Wallet with private key, connect it to local provider
|
|
278
|
+
contractWallet = new ethers_1.ethers.Wallet(this.config.contractSigner.privateKey, this.provider);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
// If signer is already connected (e.g., MetaMask), use it directly
|
|
282
|
+
contractWallet = this.config.contractSigner;
|
|
283
|
+
}
|
|
284
|
+
return contractWallet;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Create PKP with retry logic for LIT Protocol network issues
|
|
288
|
+
*/
|
|
289
|
+
async createPKPWithRetry(litOpsWallet) {
|
|
290
|
+
let pkpResult;
|
|
291
|
+
let retryAttempted = false;
|
|
292
|
+
// Attempt PKP creation with retry logic for LIT Protocol network issues
|
|
293
|
+
try {
|
|
294
|
+
pkpResult = await this.litOps.getNewDiamondHandsLoanPkp(litOpsWallet // Use LIT-Ops wallet for PKP operations
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
// Check if this is the known LIT SDK event parsing issue
|
|
299
|
+
if (!retryAttempted &&
|
|
300
|
+
error.message?.includes("Cannot read properties of undefined (reading 'topics')")) {
|
|
301
|
+
if (this.config.debug) {
|
|
302
|
+
console.log("โ ๏ธ LIT SDK event parsing failed, retrying once...");
|
|
303
|
+
}
|
|
304
|
+
retryAttempted = true;
|
|
305
|
+
// Wait a bit for network to settle
|
|
306
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
307
|
+
// Retry once
|
|
308
|
+
try {
|
|
309
|
+
pkpResult = await this.litOps.getNewDiamondHandsLoanPkp(litOpsWallet // Use LIT-Ops wallet for retry too
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
catch (retryError) {
|
|
313
|
+
if (this.config.debug) {
|
|
314
|
+
console.log("โ Retry also failed, this is a persistent LIT Protocol issue");
|
|
315
|
+
}
|
|
316
|
+
throw new Error(`PKP creation failed after retry: ${retryError instanceof Error ? retryError.message : retryError}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return pkpResult;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Process loan creation after PKP is created - handle signature extraction and contract calls
|
|
327
|
+
*/
|
|
328
|
+
async processLoanCreation(pkpResult, contractWallet, request, isServiceMode = false) {
|
|
329
|
+
// Extract PKP data from result (following the test logic)
|
|
330
|
+
let createdPkpTokenId;
|
|
331
|
+
let createdPkpAddress;
|
|
332
|
+
let createdPkpPublicKey;
|
|
333
|
+
if (pkpResult.pkpData) {
|
|
334
|
+
createdPkpTokenId = pkpResult.pkpData.tokenId || "";
|
|
335
|
+
createdPkpAddress = pkpResult.pkpData.ethAddress || "";
|
|
336
|
+
createdPkpPublicKey = pkpResult.pkpData.publicKey || "";
|
|
337
|
+
if (this.config.debug) {
|
|
338
|
+
console.log("โ
Using PKP data from main result");
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else if (pkpResult.auditTrail &&
|
|
342
|
+
pkpResult.auditTrail.steps &&
|
|
343
|
+
pkpResult.auditTrail.steps.length > 0) {
|
|
344
|
+
const creationStep = pkpResult.auditTrail.steps.find((step) => step.description.includes("Create production PKP") && step.data);
|
|
345
|
+
if (creationStep && creationStep.data) {
|
|
346
|
+
createdPkpTokenId = creationStep.data.tokenId;
|
|
347
|
+
createdPkpAddress = creationStep.data.ethAddress;
|
|
348
|
+
createdPkpPublicKey = creationStep.data.publicKey;
|
|
349
|
+
if (this.config.debug) {
|
|
350
|
+
console.log("โ
Using PKP data from audit trail");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
throw new Error("No valid PKP data found in result or audit trail");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
throw new Error("PKP creation failed completely with no audit trail");
|
|
359
|
+
}
|
|
360
|
+
if (this.config.debug) {
|
|
361
|
+
console.log("โ
PKP Data Extracted:");
|
|
362
|
+
console.log(` Token ID: ${createdPkpTokenId}`);
|
|
363
|
+
console.log(` ETH Address: ${createdPkpAddress}`);
|
|
364
|
+
console.log(` Public Key: ${createdPkpPublicKey}`);
|
|
365
|
+
}
|
|
366
|
+
// Step 2: Extract the validator signature from the PKP creation result
|
|
367
|
+
if (this.config.debug) {
|
|
368
|
+
console.log("๐ Step 2: Extracting validator signature from PKP creation");
|
|
369
|
+
}
|
|
370
|
+
let validatorSignature;
|
|
371
|
+
if (isServiceMode) {
|
|
372
|
+
// Service mode: Use signature from service response
|
|
373
|
+
if (pkpResult.pkpData?.validationSignature) {
|
|
374
|
+
validatorSignature = pkpResult.pkpData.validationSignature;
|
|
375
|
+
if (this.config.debug) {
|
|
376
|
+
console.log(`โ
Service mode: Validator signature extracted: ${validatorSignature}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else if (pkpResult.validationResult?.signature) {
|
|
380
|
+
// Fallback to validation result
|
|
381
|
+
validatorSignature = pkpResult.validationResult.signature;
|
|
382
|
+
if (this.config.debug) {
|
|
383
|
+
console.log(`โ
Service mode: Validator signature extracted (fallback): ${validatorSignature}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
throw new Error("Service response missing validation signature");
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
// Standalone mode: Extract signature from PKP result
|
|
392
|
+
// The signature is in the signatures.pkpValidation.signature field
|
|
393
|
+
if (pkpResult.signatures &&
|
|
394
|
+
pkpResult.signatures.pkpValidation &&
|
|
395
|
+
pkpResult.signatures.pkpValidation.signature) {
|
|
396
|
+
validatorSignature = pkpResult.signatures.pkpValidation.signature;
|
|
397
|
+
if (this.config.debug) {
|
|
398
|
+
console.log(`โ
Validator signature extracted: ${validatorSignature}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
else if (pkpResult.validationResult &&
|
|
402
|
+
pkpResult.validationResult.signature) {
|
|
403
|
+
// Fallback to old structure
|
|
404
|
+
validatorSignature = pkpResult.validationResult.signature;
|
|
405
|
+
if (this.config.debug) {
|
|
406
|
+
console.log(`โ
Validator signature extracted (fallback): ${validatorSignature}`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
if (this.config.debug) {
|
|
411
|
+
console.log("PKP Result structure:", JSON.stringify(pkpResult, null, 2));
|
|
412
|
+
}
|
|
413
|
+
throw new Error("No validator signature found in PKP creation result");
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const signature = validatorSignature;
|
|
417
|
+
if (this.config.debug) {
|
|
418
|
+
console.log(`โ
PKP Signature ready: ${signature}`);
|
|
419
|
+
}
|
|
420
|
+
// Convert tokenId to bytes32 for contract calls
|
|
421
|
+
const pkpId = ethers_1.ethers.utils.hexZeroPad(ethers_1.ethers.utils.hexlify(createdPkpTokenId), 32);
|
|
422
|
+
// Step 3: Prepare and execute contract transaction
|
|
423
|
+
if (this.config.debug) {
|
|
424
|
+
console.log("๐ Step 3: Executing smart contract transaction");
|
|
425
|
+
}
|
|
426
|
+
// Check if wallet needs funding
|
|
427
|
+
const contractWalletAddress = await contractWallet.getAddress();
|
|
428
|
+
const walletBalance = await this.provider.getBalance(contractWalletAddress);
|
|
429
|
+
if (walletBalance.lt(ethers_1.ethers.utils.parseEther("0.1"))) {
|
|
430
|
+
if (this.config.debug) {
|
|
431
|
+
console.log(`๐ฐ Contract wallet balance low (${ethers_1.ethers.utils.formatEther(walletBalance)} ETH), funding may be required`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// Prepare contract interaction using contract wallet
|
|
435
|
+
const contract = new ethers_1.ethers.Contract(this.config.contractAddresses.positionManager, POSITION_MANAGER_ABI, contractWallet // Use contract wallet for local network operations
|
|
436
|
+
);
|
|
437
|
+
// Convert collateralAmount from BTC to satoshis (8 decimal places)
|
|
438
|
+
// Note: collateralAmount should be in BTC units as per contract interface
|
|
439
|
+
const amount = ethers_1.ethers.utils.parseUnits(request.collateralAmount.toString(), 8); // Convert collateralAmount (BTC) to satoshis for contract call
|
|
440
|
+
// Convert collateralRatio to basis points (multiply by 100)
|
|
441
|
+
const requestedCollateralRatioBasisPoints = request.collateralRatio * 100;
|
|
442
|
+
if (this.config.debug) {
|
|
443
|
+
console.log("๐ Calling smart contract createPosition");
|
|
444
|
+
console.log(` PKP ID (bytes32): ${pkpId}`);
|
|
445
|
+
console.log(` Amount: ${amount}`);
|
|
446
|
+
console.log(` Requested Collateral Ratio: ${requestedCollateralRatioBasisPoints} (${request.collateralRatio}%)`);
|
|
447
|
+
console.log(` Selected Term: ${request.selectedTerm} months`);
|
|
448
|
+
console.log(` Signature: ${signature}`);
|
|
449
|
+
console.log(` Contract: ${this.config.contractAddresses.positionManager}`);
|
|
450
|
+
}
|
|
451
|
+
// Step 4: Call smart contract createPosition with validator signature and new parameters
|
|
452
|
+
const tx = await contract.createPosition(pkpId, amount, requestedCollateralRatioBasisPoints, request.selectedTerm, signature);
|
|
453
|
+
const receipt = await tx.wait();
|
|
454
|
+
if (this.config.debug) {
|
|
455
|
+
console.log("โ
Position created successfully!");
|
|
456
|
+
console.log(` Transaction hash: ${tx.hash}`);
|
|
457
|
+
console.log(` Gas used: ${receipt.gasUsed}`);
|
|
458
|
+
console.log(` Collateral Ratio: ${request.collateralRatio}%`);
|
|
459
|
+
console.log(` Loan Term: ${request.selectedTerm} months`);
|
|
460
|
+
console.log(` Mode: ${isServiceMode ? "service" : "standalone"}`);
|
|
461
|
+
}
|
|
462
|
+
// Extract position ID from events
|
|
463
|
+
const positionCreatedEvent = receipt.logs?.find((log) => {
|
|
464
|
+
try {
|
|
465
|
+
const parsed = contract.interface.parseLog(log);
|
|
466
|
+
return parsed?.name === "PositionCreated";
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
let positionId;
|
|
473
|
+
if (positionCreatedEvent) {
|
|
474
|
+
const parsed = contract.interface.parseLog(positionCreatedEvent);
|
|
475
|
+
positionId = parsed?.args?.positionId || "";
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
// Fallback: generate position ID
|
|
479
|
+
const borrowerAddress = await contractWallet.getAddress();
|
|
480
|
+
positionId = ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.solidityPack(["bytes32", "address", "uint256"], [pkpId, borrowerAddress, Date.now()]));
|
|
481
|
+
}
|
|
482
|
+
// Generate Bitcoin addresses from PKP public key (if available)
|
|
483
|
+
let btcAddresses;
|
|
484
|
+
if (createdPkpPublicKey) {
|
|
485
|
+
btcAddresses = (0, utils_1.getBitcoinAddressesFromPkp)(createdPkpPublicKey);
|
|
486
|
+
if (this.config.debug) {
|
|
487
|
+
console.log("๐ Step 4: Bitcoin addresses generated from PKP");
|
|
488
|
+
console.log(` Mainnet: ${btcAddresses.mainnet}`);
|
|
489
|
+
console.log(` Testnet: ${btcAddresses.testnet}`);
|
|
490
|
+
console.log(` Regtest: ${btcAddresses.regtest}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return {
|
|
494
|
+
success: true,
|
|
495
|
+
transactionHash: tx.hash,
|
|
496
|
+
positionId: positionId,
|
|
497
|
+
pkpData: {
|
|
498
|
+
tokenId: createdPkpTokenId,
|
|
499
|
+
publicKey: createdPkpPublicKey,
|
|
500
|
+
ethAddress: createdPkpAddress,
|
|
501
|
+
validationSignature: validatorSignature,
|
|
502
|
+
btcAddresses: btcAddresses || {
|
|
503
|
+
mainnet: "",
|
|
504
|
+
testnet: "",
|
|
505
|
+
regtest: "",
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
auditTrail: {
|
|
509
|
+
pkpCreation: pkpResult.auditTrail,
|
|
510
|
+
validation: { signatureGeneration: validatorSignature },
|
|
511
|
+
contractCall: {
|
|
512
|
+
transactionHash: tx.hash,
|
|
513
|
+
positionId: positionId,
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Get single loan by vault address
|
|
520
|
+
*/
|
|
521
|
+
async getLoan(vaultAddress) {
|
|
522
|
+
this.ensureInitialized();
|
|
523
|
+
try {
|
|
524
|
+
const contract = new ethers_1.ethers.Contract(this.config.contractAddresses.positionManager, POSITION_MANAGER_ABI, this.provider);
|
|
525
|
+
// For now, we'll need to implement position lookup by vault address
|
|
526
|
+
// This would require additional contract methods or event querying
|
|
527
|
+
// Placeholder implementation:
|
|
528
|
+
throw new Error("getLoan not implemented yet - requires contract method to lookup by vault address");
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
if (this.config.debug) {
|
|
532
|
+
console.error("Failed to get loan:", error);
|
|
533
|
+
}
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Get loans by various criteria
|
|
539
|
+
*/
|
|
540
|
+
async getLoans(query) {
|
|
541
|
+
this.ensureInitialized();
|
|
542
|
+
try {
|
|
543
|
+
// This would require implementing query methods in the smart contract
|
|
544
|
+
// or querying events from the blockchain
|
|
545
|
+
throw new Error("getLoans not implemented yet - requires contract query methods");
|
|
546
|
+
}
|
|
547
|
+
catch (error) {
|
|
548
|
+
if (this.config.debug) {
|
|
549
|
+
console.error("Failed to get loans:", error);
|
|
550
|
+
}
|
|
551
|
+
return [];
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Get all positions for a user
|
|
556
|
+
*/
|
|
557
|
+
async getUserPositions(userAddress) {
|
|
558
|
+
this.ensureInitialized();
|
|
559
|
+
try {
|
|
560
|
+
if (this.config.debug) {
|
|
561
|
+
console.log(`๐ Getting positions for user: ${userAddress}`);
|
|
562
|
+
}
|
|
563
|
+
const contract = new ethers_1.ethers.Contract(this.config.contractAddresses.positionManager, POSITION_MANAGER_ABI, this.provider);
|
|
564
|
+
// Call contract method to get user positions
|
|
565
|
+
const positionIds = await contract.getUserPositions(userAddress);
|
|
566
|
+
if (this.config.debug) {
|
|
567
|
+
console.log(` Found ${positionIds.length} positions`);
|
|
568
|
+
}
|
|
569
|
+
// Get details for each position
|
|
570
|
+
const positions = [];
|
|
571
|
+
for (const positionId of positionIds) {
|
|
572
|
+
try {
|
|
573
|
+
const positionDetails = await contract.getPositionDetails(positionId);
|
|
574
|
+
positions.push({
|
|
575
|
+
positionId: positionDetails.positionId,
|
|
576
|
+
pkpId: positionDetails.pkpId,
|
|
577
|
+
vaultAddress: positionDetails.pkpId, // Using pkpId as vault address for now
|
|
578
|
+
borrower: positionDetails.borrower,
|
|
579
|
+
collateralAmount: parseInt(ethers_1.ethers.utils.formatUnits(positionDetails.btcAmount, 8)),
|
|
580
|
+
ucdDebt: parseInt(ethers_1.ethers.utils.formatEther(positionDetails.ucdDebt)),
|
|
581
|
+
collateralRatio: positionDetails.collateralRatio,
|
|
582
|
+
status: positionDetails.isActive ? "active" : "closed",
|
|
583
|
+
createdAt: positionDetails.createdAt.toNumber(),
|
|
584
|
+
lastUpdated: positionDetails.lastUpdated.toNumber(),
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
catch (error) {
|
|
588
|
+
if (this.config.debug) {
|
|
589
|
+
console.warn(`Failed to get details for position ${positionId}:`, error);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return positions;
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
if (this.config.debug) {
|
|
597
|
+
console.error("Failed to get user positions:", error);
|
|
598
|
+
}
|
|
599
|
+
return [];
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Get position details by PKP ID
|
|
604
|
+
*/
|
|
605
|
+
async getPositionByPKP(pkpId) {
|
|
606
|
+
this.ensureInitialized();
|
|
607
|
+
try {
|
|
608
|
+
if (this.config.debug) {
|
|
609
|
+
console.log(`๐ Getting position for PKP: ${pkpId}`);
|
|
610
|
+
}
|
|
611
|
+
const contract = new ethers_1.ethers.Contract(this.config.contractAddresses.positionManager, POSITION_MANAGER_ABI, this.provider);
|
|
612
|
+
// Convert PKP ID to bytes32 if needed
|
|
613
|
+
const pkpIdBytes32 = ethers_1.ethers.utils.hexZeroPad(pkpId, 32);
|
|
614
|
+
// Get position ID from PKP
|
|
615
|
+
const positionId = await contract.getPositionByPKP(pkpIdBytes32);
|
|
616
|
+
if (positionId === ethers_1.ethers.constants.HashZero) {
|
|
617
|
+
if (this.config.debug) {
|
|
618
|
+
console.log(" No position found for this PKP");
|
|
619
|
+
}
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
// Get position details
|
|
623
|
+
const positionDetails = await contract.getPositionDetails(positionId);
|
|
624
|
+
return {
|
|
625
|
+
positionId: positionDetails.positionId,
|
|
626
|
+
pkpId: positionDetails.pkpId,
|
|
627
|
+
vaultAddress: positionDetails.pkpId, // Using pkpId as vault address for now
|
|
628
|
+
borrower: positionDetails.borrower,
|
|
629
|
+
collateralAmount: parseInt(ethers_1.ethers.utils.formatUnits(positionDetails.btcAmount, 8)),
|
|
630
|
+
ucdDebt: parseInt(ethers_1.ethers.utils.formatEther(positionDetails.ucdDebt)),
|
|
631
|
+
collateralRatio: positionDetails.collateralRatio,
|
|
632
|
+
status: positionDetails.isActive ? "active" : "closed",
|
|
633
|
+
createdAt: positionDetails.createdAt.toNumber(),
|
|
634
|
+
lastUpdated: positionDetails.lastUpdated.toNumber(),
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
if (this.config.debug) {
|
|
639
|
+
console.error("Failed to get position by PKP:", error);
|
|
640
|
+
}
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Get PKP loan parameters (amount, collateral ratio, term) directly by PKP ID
|
|
646
|
+
* This uses the optimized storage for quick access to core loan parameters
|
|
647
|
+
*/
|
|
648
|
+
async getPKPLoanParams(pkpId) {
|
|
649
|
+
this.ensureInitialized();
|
|
650
|
+
try {
|
|
651
|
+
if (this.config.debug) {
|
|
652
|
+
console.log(`๐ Getting PKP loan parameters for PKP: ${pkpId}`);
|
|
653
|
+
}
|
|
654
|
+
const contract = new ethers_1.ethers.Contract(this.config.contractAddresses.positionManager, POSITION_MANAGER_ABI, this.provider);
|
|
655
|
+
// Convert PKP ID to bytes32 if needed
|
|
656
|
+
const pkpIdBytes32 = ethers_1.ethers.utils.hexZeroPad(pkpId, 32);
|
|
657
|
+
// Get loan parameters directly from PKP storage
|
|
658
|
+
const [amount, requestedCollateralRatio, selectedTerm] = await contract.getPKPLoanParams(pkpIdBytes32);
|
|
659
|
+
if (amount.eq(0)) {
|
|
660
|
+
if (this.config.debug) {
|
|
661
|
+
console.log(" No loan parameters found for this PKP");
|
|
662
|
+
}
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
const result = {
|
|
666
|
+
amount: parseInt(ethers_1.ethers.utils.formatUnits(amount, 8)),
|
|
667
|
+
requestedCollateralRatio: requestedCollateralRatio.toNumber() / 100, // Convert from basis points
|
|
668
|
+
selectedTerm: selectedTerm.toNumber(),
|
|
669
|
+
};
|
|
670
|
+
if (this.config.debug) {
|
|
671
|
+
console.log(` Amount: ${result.amount} BTC`);
|
|
672
|
+
console.log(` Collateral Ratio: ${result.requestedCollateralRatio}%`);
|
|
673
|
+
console.log(` Term: ${result.selectedTerm} months`);
|
|
674
|
+
}
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
if (this.config.debug) {
|
|
679
|
+
console.error("Failed to get PKP loan parameters:", error);
|
|
680
|
+
}
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Get complete PKP position data by PKP ID
|
|
686
|
+
* This provides all stored PKP position information in one call
|
|
687
|
+
*/
|
|
688
|
+
async getPKPPositionData(pkpId) {
|
|
689
|
+
this.ensureInitialized();
|
|
690
|
+
try {
|
|
691
|
+
if (this.config.debug) {
|
|
692
|
+
console.log(`๐ Getting complete PKP position data for PKP: ${pkpId}`);
|
|
693
|
+
}
|
|
694
|
+
const contract = new ethers_1.ethers.Contract(this.config.contractAddresses.positionManager, POSITION_MANAGER_ABI, this.provider);
|
|
695
|
+
// Convert PKP ID to bytes32 if needed
|
|
696
|
+
const pkpIdBytes32 = ethers_1.ethers.utils.hexZeroPad(pkpId, 32);
|
|
697
|
+
// Get complete PKP position data
|
|
698
|
+
const pkpData = await contract.getPKPPositionData(pkpIdBytes32);
|
|
699
|
+
if (!pkpData.isActive && pkpData.amount.eq(0)) {
|
|
700
|
+
if (this.config.debug) {
|
|
701
|
+
console.log(" No position data found for this PKP");
|
|
702
|
+
}
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
return {
|
|
706
|
+
positionId: pkpData.positionId,
|
|
707
|
+
borrower: pkpData.borrower,
|
|
708
|
+
amount: parseInt(ethers_1.ethers.utils.formatUnits(pkpData.amount, 8)),
|
|
709
|
+
requestedCollateralRatio: pkpData.requestedCollateralRatio.toNumber() / 100, // Convert from basis points
|
|
710
|
+
selectedTerm: pkpData.selectedTerm.toNumber(),
|
|
711
|
+
createdAt: pkpData.createdAt.toNumber(),
|
|
712
|
+
isActive: pkpData.isActive,
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
catch (error) {
|
|
716
|
+
if (this.config.debug) {
|
|
717
|
+
console.error("Failed to get PKP position data:", error);
|
|
718
|
+
}
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Request UCD minting for a loan
|
|
724
|
+
*/
|
|
725
|
+
async requestMintUCD(request) {
|
|
726
|
+
this.ensureInitialized();
|
|
727
|
+
try {
|
|
728
|
+
if (this.config.debug) {
|
|
729
|
+
console.log("๐ช Requesting UCD minting...");
|
|
730
|
+
}
|
|
731
|
+
// This would call the mintUCD method on the position manager contract
|
|
732
|
+
throw new Error("requestMintUCD not implemented yet - requires mintUCD contract method");
|
|
733
|
+
}
|
|
734
|
+
catch (error) {
|
|
735
|
+
throw new Error(`UCD minting failed: ${error instanceof Error ? error.message : error}`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Request loan liquidation
|
|
740
|
+
*/
|
|
741
|
+
async requestLiquidation(request) {
|
|
742
|
+
this.ensureInitialized();
|
|
743
|
+
try {
|
|
744
|
+
if (this.config.debug) {
|
|
745
|
+
console.log("โก Requesting loan liquidation...");
|
|
746
|
+
}
|
|
747
|
+
// This would call the liquidatePosition method on the position manager contract
|
|
748
|
+
throw new Error("requestLiquidation not implemented yet - requires liquidatePosition contract method");
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
throw new Error(`Liquidation failed: ${error instanceof Error ? error.message : error}`);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Cleanup SDK resources
|
|
756
|
+
*/
|
|
757
|
+
async destroy() {
|
|
758
|
+
if (this.litOps) {
|
|
759
|
+
await this.litOps.disconnect();
|
|
760
|
+
this.litOps = null;
|
|
761
|
+
}
|
|
762
|
+
this.initialized = false;
|
|
763
|
+
if (this.config.debug) {
|
|
764
|
+
console.log("๐งน SDK cleanup complete");
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
ensureInitialized() {
|
|
768
|
+
if (!this.initialized) {
|
|
769
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
exports.DiamondHandsSDK = DiamondHandsSDK;
|