@gvnrdao/dh-lit-actions 0.0.281 → 0.0.282
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/dist/address-probe-signer.meta.json +1 -1
- package/dist/address-probe.meta.json +1 -1
- package/dist/admin-liquidation-validator.action.js +1 -1
- package/dist/admin-liquidation-validator.hash +1 -1
- package/dist/admin-liquidation-validator.meta.json +5 -5
- package/dist/always-signer.meta.json +1 -1
- package/dist/authorization-dummy-b.meta.json +1 -1
- package/dist/authorization-dummy.meta.json +1 -1
- package/dist/btc-transaction-signer.meta.json +5 -5
- package/dist/btc-withdrawal.action.js +1 -1
- package/dist/btc-withdrawal.hash +1 -1
- package/dist/btc-withdrawal.meta.json +5 -5
- package/dist/encrypt-parameter.meta.json +1 -1
- package/dist/extend-position-validator.action.js +1 -1
- package/dist/extend-position-validator.hash +1 -1
- package/dist/extend-position-validator.meta.json +5 -5
- package/dist/liquidation-validator.action.js +1 -1
- package/dist/liquidation-validator.hash +1 -1
- package/dist/liquidation-validator.meta.json +5 -5
- package/dist/loan-vault-btc-balance.action.js +1 -1
- package/dist/loan-vault-btc-balance.hash +1 -1
- package/dist/loan-vault-btc-balance.meta.json +5 -5
- package/dist/pkp-validator.meta.json +5 -5
- package/dist/price-oracle.action.js +1 -1
- package/dist/price-oracle.hash +1 -1
- package/dist/price-oracle.meta.json +5 -5
- package/dist/process-payment-sign-only.meta.json +1 -1
- package/dist/process-payment-validator.action.js +1 -1
- package/dist/process-payment-validator.hash +1 -1
- package/dist/process-payment-validator.meta.json +5 -5
- package/dist/ucd-mint-validator.action.js +1 -1
- package/dist/ucd-mint-validator.hash +1 -1
- package/dist/ucd-mint-validator.meta.json +5 -5
- package/package.json +1 -1
- package/pkg-dist/package.json +1 -0
- package/pkg-dist/pkg-src/index.js +1587 -36
- package/pkg-dist/pkg-src/index.js.map +7 -1
- package/pkg-dist/src/modules/price-oracle.module.d.ts +11 -14
- package/pkg-dist/src/modules/price-oracle.module.d.ts.map +1 -1
- package/pkg-dist/pkg-src/constants/chunks/lit-actions-registry.js +0 -206
- package/pkg-dist/pkg-src/constants/chunks/lit-actions-registry.js.map +0 -1
- package/pkg-dist/pkg-src/constants/chunks/package-registry.js +0 -12
- package/pkg-dist/pkg-src/constants/chunks/package-registry.js.map +0 -1
- package/pkg-dist/pkg-src/constants/index.js +0 -23
- package/pkg-dist/pkg-src/constants/index.js.map +0 -1
- package/pkg-dist/pkg-src/executors/chunks/price-oracle-executor.js +0 -77
- package/pkg-dist/pkg-src/executors/chunks/price-oracle-executor.js.map +0 -1
- package/pkg-dist/pkg-src/executors/chunks/vault-snapshot-executor.js +0 -104
- package/pkg-dist/pkg-src/executors/chunks/vault-snapshot-executor.js.map +0 -1
- package/pkg-dist/pkg-src/executors/index.js +0 -88
- package/pkg-dist/pkg-src/executors/index.js.map +0 -1
- package/pkg-dist/pkg-src/interfaces/chunks/diamond-hands-lit-actions.i.js +0 -3
- package/pkg-dist/pkg-src/interfaces/chunks/diamond-hands-lit-actions.i.js.map +0 -1
- package/pkg-dist/pkg-src/interfaces/chunks/lit-action-config.i.js +0 -3
- package/pkg-dist/pkg-src/interfaces/chunks/lit-action-config.i.js.map +0 -1
- package/pkg-dist/pkg-src/interfaces/chunks/lit-action-name.i.js +0 -3
- package/pkg-dist/pkg-src/interfaces/chunks/lit-action-name.i.js.map +0 -1
- package/pkg-dist/pkg-src/interfaces/chunks/lit-action-registry.i.js +0 -3
- package/pkg-dist/pkg-src/interfaces/chunks/lit-action-registry.i.js.map +0 -1
- package/pkg-dist/pkg-src/interfaces/chunks/pkp-info.i.js +0 -3
- package/pkg-dist/pkg-src/interfaces/chunks/pkp-info.i.js.map +0 -1
- package/pkg-dist/pkg-src/interfaces/index.js +0 -25
- package/pkg-dist/pkg-src/interfaces/index.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/cid-utils.js +0 -37
- package/pkg-dist/pkg-src/utils/chunks/cid-utils.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/connection-helpers.js +0 -354
- package/pkg-dist/pkg-src/utils/chunks/connection-helpers.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/debug-logger.js +0 -264
- package/pkg-dist/pkg-src/utils/chunks/debug-logger.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/error-classification.js +0 -385
- package/pkg-dist/pkg-src/utils/chunks/error-classification.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/lit-action-helpers.js +0 -62
- package/pkg-dist/pkg-src/utils/chunks/lit-action-helpers.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/pkp-setup.js +0 -21
- package/pkg-dist/pkg-src/utils/chunks/pkp-setup.js.map +0 -1
- package/pkg-dist/pkg-src/utils/chunks/session-signature-cache.js +0 -194
- package/pkg-dist/pkg-src/utils/chunks/session-signature-cache.js.map +0 -1
- package/pkg-dist/pkg-src/utils/index.js +0 -28
- package/pkg-dist/pkg-src/utils/index.js.map +0 -1
- package/pkg-dist/src/constants/chunks/bitcoin-network-config.js +0 -236
- package/pkg-dist/src/constants/chunks/bitcoin-network-config.js.map +0 -1
- package/pkg-dist/src/constants/chunks/bitcoin.js +0 -87
- package/pkg-dist/src/constants/chunks/bitcoin.js.map +0 -1
- package/pkg-dist/src/constants/chunks/decimals.js +0 -47
- package/pkg-dist/src/constants/chunks/decimals.js.map +0 -1
- package/pkg-dist/src/constants/chunks/liquidation.js +0 -46
- package/pkg-dist/src/constants/chunks/liquidation.js.map +0 -1
- package/pkg-dist/src/constants/chunks/lit-action-runtime.js +0 -10
- package/pkg-dist/src/constants/chunks/lit-action-runtime.js.map +0 -1
- package/pkg-dist/src/constants/chunks/loan-status.js +0 -95
- package/pkg-dist/src/constants/chunks/loan-status.js.map +0 -1
- package/pkg-dist/src/constants/chunks/price-oracle.js +0 -49
- package/pkg-dist/src/constants/chunks/price-oracle.js.map +0 -1
- package/pkg-dist/src/constants/chunks/quantum-time.js +0 -81
- package/pkg-dist/src/constants/chunks/quantum-time.js.map +0 -1
- package/pkg-dist/src/constants/chunks/time.js +0 -53
- package/pkg-dist/src/constants/chunks/time.js.map +0 -1
- package/pkg-dist/src/constants/index.js +0 -88
- package/pkg-dist/src/constants/index.js.map +0 -1
- package/pkg-dist/src/constants/message-hash-domains.js +0 -39
- package/pkg-dist/src/constants/message-hash-domains.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/authorization.i.js +0 -3
- package/pkg-dist/src/interfaces/chunks/authorization.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/bitcoin-data-provider.i.js +0 -3
- package/pkg-dist/src/interfaces/chunks/bitcoin-data-provider.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/circuit-breaker.i.js +0 -8
- package/pkg-dist/src/interfaces/chunks/circuit-breaker.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/mint-authorization.i.js +0 -5
- package/pkg-dist/src/interfaces/chunks/mint-authorization.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/owner-authorization.js +0 -8
- package/pkg-dist/src/interfaces/chunks/owner-authorization.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/price-oracle.i.js +0 -3
- package/pkg-dist/src/interfaces/chunks/price-oracle.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/vault-balance-module.i.js +0 -3
- package/pkg-dist/src/interfaces/chunks/vault-balance-module.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/vault-balance.i.js +0 -3
- package/pkg-dist/src/interfaces/chunks/vault-balance.i.js.map +0 -1
- package/pkg-dist/src/interfaces/chunks/vault-snapshot.i.js +0 -3
- package/pkg-dist/src/interfaces/chunks/vault-snapshot.i.js.map +0 -1
- package/pkg-dist/src/interfaces/index.js +0 -30
- package/pkg-dist/src/interfaces/index.js.map +0 -1
- package/pkg-dist/src/modules/authorization.module.js +0 -479
- package/pkg-dist/src/modules/authorization.module.js.map +0 -1
- package/pkg-dist/src/modules/bitcoin/address.js +0 -323
- package/pkg-dist/src/modules/bitcoin/address.js.map +0 -1
- package/pkg-dist/src/modules/bitcoin/provider.js +0 -67
- package/pkg-dist/src/modules/bitcoin/provider.js.map +0 -1
- package/pkg-dist/src/modules/bitcoin/signature.js +0 -64
- package/pkg-dist/src/modules/bitcoin/signature.js.map +0 -1
- package/pkg-dist/src/modules/bitcoin/transaction.js +0 -274
- package/pkg-dist/src/modules/bitcoin/transaction.js.map +0 -1
- package/pkg-dist/src/modules/bitcoin-data-provider.module.js +0 -534
- package/pkg-dist/src/modules/bitcoin-data-provider.module.js.map +0 -1
- package/pkg-dist/src/modules/bitcoin-provider-registry.js +0 -165
- package/pkg-dist/src/modules/bitcoin-provider-registry.js.map +0 -1
- package/pkg-dist/src/modules/business-rules-math.module.js +0 -316
- package/pkg-dist/src/modules/business-rules-math.module.js.map +0 -1
- package/pkg-dist/src/modules/chain-policy.js +0 -90
- package/pkg-dist/src/modules/chain-policy.js.map +0 -1
- package/pkg-dist/src/modules/dev-action-guard.js +0 -47
- package/pkg-dist/src/modules/dev-action-guard.js.map +0 -1
- package/pkg-dist/src/modules/lit-action-debug.js +0 -85
- package/pkg-dist/src/modules/lit-action-debug.js.map +0 -1
- package/pkg-dist/src/modules/lit-action-logger.module.js +0 -190
- package/pkg-dist/src/modules/lit-action-logger.module.js.map +0 -1
- package/pkg-dist/src/modules/lit-global-bootstrap.js +0 -65
- package/pkg-dist/src/modules/lit-global-bootstrap.js.map +0 -1
- package/pkg-dist/src/modules/position-id.js +0 -40
- package/pkg-dist/src/modules/position-id.js.map +0 -1
- package/pkg-dist/src/modules/price-oracle.module.js +0 -513
- package/pkg-dist/src/modules/price-oracle.module.js.map +0 -1
- package/pkg-dist/src/modules/pro-rata-fee.module.js +0 -66
- package/pkg-dist/src/modules/pro-rata-fee.module.js.map +0 -1
- package/pkg-dist/src/modules/protocol-parameters.module.js +0 -216
- package/pkg-dist/src/modules/protocol-parameters.module.js.map +0 -1
- package/pkg-dist/src/modules/protocol-pause.module.js +0 -227
- package/pkg-dist/src/modules/protocol-pause.module.js.map +0 -1
- package/pkg-dist/src/modules/quantum-time.module.js +0 -320
- package/pkg-dist/src/modules/quantum-time.module.js.map +0 -1
- package/pkg-dist/src/modules/vault-balance.module.js +0 -428
- package/pkg-dist/src/modules/vault-balance.module.js.map +0 -1
- package/pkg-dist/src/modules/vault-snapshot.js +0 -517
- package/pkg-dist/src/modules/vault-snapshot.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
var _LIT_ACTION_=(()=>{var e=Object.defineProperty,t=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.prototype.hasOwnProperty,a={};((t,r)=>{for(var i in r)e(t,i,{get:r[i],enumerable:!0})})(a,{main:()=>main});var o=11e3,n=1000000000000000000n,s=1000000000000n,c=100000000000000n,l=100,u=10,d=8e3;function p(e){switch(e){case 0:return"PENDING_DEPOSIT";case 1:return"PENDING_MINT";case 2:return"ACTIVE";case 3:return"EXPIRED";case 4:return"LIQUIDATABLE";case 5:return"LIQUIDATED";case 6:return"REPAID";case 7:return"CLOSED";default:return`UNKNOWN(${e})`}}var h="DiamondHands.Protocol",g="1",m="admin-liquidation",f=(e=>(e.SEPOLIA="sepolia",e.ETHEREUM="ethereum",e.HARDHAT="hardhat",e))(f||{}),w={sepolia:"testnet",ethereum:"mainnet",hardhat:"regtest"},y=["infura.io","drpc.org"],b={ethereum:1,sepolia:11155111,hardhat:1337};function T(e){const t=e.toLowerCase().trim();if("sepolia"===t)return"sepolia";if("ethereum"===t||"mainnet"===t)return"ethereum";if("hardhat"===t)return"hardhat";throw new Error(`Unsupported EVM chain: "${e}". Supported chains: ${Object.values(f).join(", ")}`)}function P(e){return b[e]}function v(e){if(!0===e)return!0;if(!1===e)return!1;const t=globalThis;return!0===t.debugAction||(!0===t.LIT_ACTION_DEBUG||("true"===t.LIT_ACTION_DEBUG||function(){try{if("undefined"==typeof process||!process.env)return!1;const e=process.env.LIT_ACTION_DEBUG,t=process.env.DEBUG;return"1"===e||"true"===e||"1"===t||"true"===t}catch{return!1}}()))}function S(...e){v()&&console.log(...e)}var E=class{stepStart(e,t){}stepEnd(e,t){}log(e,t,...r){}warn(e,t){}error(e,t){}getElapsed(){return 0}getRemaining(){return 3e4}summary(){}getExecutionId(){return""}isDebugEnabled(){return!1}},A=class{constructor(e){this.stepStartTimes=new Map,this.stepDurations=new Map,this.TIMEOUT_MS=3e4,this.actionName=e,this.executionStartTime=Date.now();const t=Date.now(),r=Math.random().toString(36).substring(2,9);this.executionId=`exec_${t}_${r}`,this.logHeader()}logHeader(){console.log(`[${this.actionName}] ========================================`),console.log(`[${this.actionName}] Execution started`),console.log(`[${this.actionName}] Execution ID: ${this.executionId}`);void 0!==globalThis.litNodeContext?(console.log(`[${this.actionName}] Context: LIT Node`),console.log(`[${this.actionName}] Node: ${globalThis.litNodeContext?.nodeAddress||"unknown"}`)):console.log(`[${this.actionName}] Context: Browser/Test`),console.log(`[${this.actionName}] ========================================`)}stepStart(e,t){this.stepStartTimes.set(e,Date.now());const r=Date.now()-this.executionStartTime,i=this.TIMEOUT_MS-r;console.log(`[Step ${e}] ${t}...`),console.log(`[Step ${e}] Elapsed: ${r}ms | Remaining: ${i}ms`)}stepEnd(e,t=5e3){const r=this.stepStartTimes.get(e);if(!r)return console.warn(`[Step ${e}] \u26a0\ufe0f stepEnd called without matching stepStart`),void 0;const i=Date.now()-r;this.stepDurations.set(e,i),console.log(`[Step ${e}] Duration: ${i}ms`),i>t&&console.warn(`\u26a0\ufe0f [Step ${e}] Took ${i}ms (> ${t}ms threshold)`);const a=Date.now()-this.executionStartTime,o=this.TIMEOUT_MS-a;o<5e3&&console.warn(`\u26a0\ufe0f [Step ${e}] Time remaining: ${o}ms (approaching timeout)`)}log(e,t,...r){r.length>0?console.log(`[Step ${e}] ${t}`,...r):console.log(`[Step ${e}] ${t}`)}warn(e,t){console.warn(`\u26a0\ufe0f [Step ${e}] ${t}`)}error(e,t){console.error(`\u274c [Step ${e}] ${t}`)}getElapsed(){return Date.now()-this.executionStartTime}getRemaining(){return this.TIMEOUT_MS-this.getElapsed()}summary(){const e=Date.now()-this.executionStartTime,t=this.TIMEOUT_MS-e;if(console.log(`[${this.actionName}] ========================================`),console.log(`[${this.actionName}] Execution Summary`),console.log(`[${this.actionName}] Execution ID: ${this.executionId}`),console.log(`[${this.actionName}] Total time: ${(e/1e3).toFixed(2)}s`),console.log(`[${this.actionName}] Time remaining: ${t}ms`),this.stepDurations.size>0){console.log(`[${this.actionName}] Step breakdown:`);for(const[t,r]of this.stepDurations.entries()){const i=(r/e*100).toFixed(1);console.log(`[${this.actionName}] Step ${t}: ${r}ms (${i}%)`)}}e>2e4&&console.warn(`\u26a0\ufe0f [${this.actionName}] Slow execution: ${(e/1e3).toFixed(2)}s (${t}ms remaining)`),t<5e3&&console.warn(`\u26a0\ufe0f [${this.actionName}] CRITICAL: Only ${t}ms remaining before timeout!`),console.log(`[${this.actionName}] ========================================`)}getExecutionId(){return this.executionId}isDebugEnabled(){return!0}},I=class{static create(e="LIT Action",t){return v(t)?new A(e):new E}};function $(e){if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function C(e){return e instanceof Error&&"AbortError"===e.name}var B=class{constructor(e){this.config=e,this.timeout=e.timeout||15e3,this.logger=I.create("BitcoinDataProvider")}async getCurrentBlockHeight(){if(this.logger.stepStart("0","getCurrentBlockHeight"),this.config.rpcHelper){const e=await this.config.rpcHelper.getBlockCount();return this.logger.stepEnd("0"),e}const e=new AbortController,t=setTimeout((()=>e.abort()),this.timeout);try{const r=Date.now(),i=await fetch(`${this.config.providerUrl}/blocks/tip/height`,{signal:e.signal,headers:{Accept:"text/plain","User-Agent":"Mozilla/5.0 (compatible; DiamondHandsValidator/1.0)","ngrok-skip-browser-warning":"true"}});if(clearTimeout(t),S(`[BitcoinDataProvider] blocks/tip/height ${Date.now()-r}ms (timeout budget ${this.timeout}ms)`),!i.ok)throw new Error(`Failed to fetch block height: ${i.status} ${i.statusText}`);const a=await i.text();if(a.trim().startsWith("<!DOCTYPE")||a.trim().startsWith("<html"))throw new Error("Bitcoin RPC endpoint returned HTML instead of block height. URL may be pointing to web interface instead of API endpoint. Expected: plain text number, Got: HTML document. Check that URL ends with /api/esplora (not root /)");const o=parseInt(a.trim(),10);if(isNaN(o)){const e=a.length>200?a.substring(0,200)+"... (truncated)":a;throw new Error(`Invalid block height response: ${e}`)}return this.logger.stepEnd("0"),o}catch(e){if(clearTimeout(t),this.logger.stepEnd("0"),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);throw e}}async getUTXOs(e){this.logger.log("0",`Original address: "${e}"`);const t=this.stripNetworkPrefix(e);if(this.logger.log("0",`Cleaned address: "${t}"`),this.config.rpcHelper)return await this.fetchUTXOsFromRPC(t);try{return await this.fetchUTXOsFromProvider(this.config.providerUrl,t)}catch(e){if(this.logger.warn("0",`Primary provider failed: ${$(e)}`),this.config.fallbackProviders&&this.config.fallbackProviders.length>0){const e=[...this.config.fallbackProviders].sort(((e,t)=>e.priority-t.priority));for(const r of e)try{return this.logger.log("0",`Trying fallback: ${r.name} (${r.url})`),await this.fetchUTXOsFromProvider(r.url,t)}catch(e){this.logger.warn("0",`Fallback ${r.name} failed: ${$(e)}`);continue}}throw new Error(`Failed to fetch UTXOs: ${$(e)}`)}}stripNetworkPrefix(e){return e.replace(/^(REGTEST_|TESTNET_|MAINNET_)/,"")}async fetchUTXOsFromRPC(e){if(!this.config.rpcHelper)throw new Error("RPC helper not configured");const t=this.config.rpcWallet||"";return(await this.config.rpcHelper.listUnspent(t,e)).map((e=>({txid:e.txid,vout:e.vout,satoshis:BigInt(Math.round(1e8*e.amount)),confirmations:e.confirmations})))}parseBlockstreamUTXOs(e,t){if(!Array.isArray(e))throw new Error("Invalid Blockstream response format: expected an array");const r=e,i=[];for(const e of r){let r=0;e.status&&"object"==typeof e.status?e.status.confirmed&&(r=void 0!==e.status.block_height&&e.status.block_height>0?t-e.status.block_height+1:1):void 0!==e.confirmations&&(r=e.confirmations);const a=e.txid,o=void 0!==e.vout?e.vout:e.n,n=void 0!==e.value?e.value:e.satoshis;if(void 0===a||void 0===o||void 0===n)throw new Error("Invalid UTXO row: missing txid, vout/n, or value/satoshis");i.push({txid:a,vout:o,satoshis:BigInt(n),confirmations:r})}return i}async fetchUTXOsFromProvider(e,t){this.logger.stepStart("1","fetchUTXOsFromProvider");const r=`${e}/address/${t}/utxos`;this.logger.log("1",`Fetching UTXOs from ${r}`);const i=new AbortController,a=setTimeout((()=>i.abort()),this.timeout);try{const e=Date.now(),[o,n]=await Promise.all([this.getCurrentBlockHeight(),fetch(r,{signal:i.signal,headers:{Accept:"application/json","Content-Type":"application/json","User-Agent":"Mozilla/5.0 (compatible; DiamondHandsValidator/1.0)","ngrok-skip-browser-warning":"true"}})]);if(clearTimeout(a),S(`[BitcoinDataProvider] parallel(tipHeight + GET utxos) wall ${Date.now()-e}ms endpoint tail .../${t.slice(0,12)}.../utxos (timeout budget ${this.timeout}ms)`),this.logger.log("1",`Current block height: ${o}`),!n.ok)throw new Error(`Bitcoin provider error: ${n.status} ${n.statusText}`);const s=await n.text();if(s.trim().startsWith("<!DOCTYPE")||s.trim().startsWith("<html"))throw new Error("Bitcoin RPC endpoint returned HTML instead of JSON. URL may be pointing to web interface instead of API endpoint. Expected: JSON array of UTXOs, Got: HTML document. Check that URL ends with /api/esplora (not root /)");let c;try{c=JSON.parse(s)}catch(e){const t=s.length>200?s.substring(0,200)+"... (truncated)":s;throw new Error(`Failed to parse JSON response: ${$(e)}. Response: ${t}`)}this.logger.log("1",`Raw API Response: ${JSON.stringify(c,null,2)}`);const l=this.parseBlockstreamUTXOs(c,o);return this.logger.stepEnd("1"),l}catch(e){if(clearTimeout(a),this.logger.stepEnd("1"),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);throw e}}async getUTXOSet(e,t){let r=[],i=null;for(let t=1;t<=3;t++)try{this.logger.log("2",`UTXO query attempt ${t}/3...`),r=await this.getUTXOs(e),this.logger.log("2",`UTXO query succeeded on attempt ${t}`),i=null;break}catch(e){i=e instanceof Error?e:new Error($(e)),this.logger.error("2",`UTXO query failed on attempt ${t}: ${$(e)}`),t<3&&(this.logger.log("2","Waiting 500ms before retry..."),await new Promise((e=>setTimeout(e,500))))}if(i)throw new Error(`Failed to query UTXOs after 3 attempts: ${i.message}`);const a=r.reduce(((e,t)=>e+t.satoshis),0n),o=r.filter((e=>e.confirmations>=t)).reduce(((e,t)=>e+t.satoshis),0n),n=a-o;return{utxos:r,totalBalance:a,totalUTXOs:r.length,confirmedBalance:o,unconfirmedBalance:n}}async getBalance(e){const t=this.stripNetworkPrefix(e),r=`${this.config.providerUrl}/address/${t}`;this.logger.log("3",`Fetching balance from ${r}`);const i=new AbortController,a=setTimeout((()=>i.abort()),this.timeout);try{const e=Date.now(),t=await fetch(r,{signal:i.signal,headers:{Accept:"application/json","Content-Type":"application/json","User-Agent":"Mozilla/5.0 (compatible; DiamondHandsValidator/1.0)","ngrok-skip-browser-warning":"true"}});if(clearTimeout(a),S(`[BitcoinDataProvider] GET address chain_stats ${Date.now()-e}ms (timeout budget ${this.timeout}ms)`),!t.ok)throw new Error(`Bitcoin provider error: ${t.status} ${t.statusText}`);const o=await t.json();if(!o.chain_stats)throw new Error("Invalid response: missing chain_stats");const n=o.chain_stats.funded_txo_sum,s=o.chain_stats.spent_txo_sum;if(void 0===n||void 0===s)throw new Error(`Invalid response: missing required fields. funded_txo_sum: ${n}, spent_txo_sum: ${s}`);const c=BigInt(n-s);return this.logger.log("3",`Balance: ${c.toString()} sats`),this.logger.log("3",` - Funded: ${n} sats, Spent: ${s} sats`),c}catch(e){if(clearTimeout(a),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);const r=$(e);throw this.logger.log("3",`Balance fetch failed: ${r}`),new Error(`Failed to fetch Bitcoin balance for address ${t}: ${r}`)}}async getTransaction(e){if(this.config.rpcHelper)try{const t=this.config.rpcWallet||"",r=await this.config.rpcHelper.getTransaction(t,e);return{txid:r.txid,confirmations:r.confirmations||0}}catch(e){const t=$(e),r=null!==e&&"object"==typeof e&&"code"in e&&"number"==typeof e.code?e.code:void 0;if(t.includes("Invalid or non-wallet transaction")||-5===r)return null;throw e}const t=new AbortController,r=setTimeout((()=>t.abort()),this.timeout);try{const i=Date.now(),a=await fetch(`${this.config.providerUrl}/tx/${e}`,{signal:t.signal});if(clearTimeout(r),S(`[BitcoinDataProvider] GET tx/${e.slice(0,10)}\u2026 ${Date.now()-i}ms (timeout budget ${this.timeout}ms)`),!a.ok){if(404===a.status)return null;throw new Error(`Bitcoin provider error: ${a.status} ${a.statusText}`)}const o=await a.json();return o.status?{txid:o.txid??e,confirmations:o.status.confirmed&&o.status.block_height?1:0}:null}catch(e){if(clearTimeout(r),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);if($(e).includes("404"))return null;throw e}}async getTransactionOutputs(e){if(!this.config.providerUrl)return null;const t=new AbortController,r=setTimeout((()=>t.abort()),this.timeout);try{const i=await fetch(`${this.config.providerUrl}/tx/${e}`,{signal:t.signal});if(clearTimeout(r),!i.ok){if(404===i.status)return null;throw new Error(`Bitcoin provider error: ${i.status} ${i.statusText}`)}const a=await i.json();return a.vout&&Array.isArray(a.vout)?a.vout.map(((e,t)=>({index:t,scriptpubkey:e.scriptpubkey,scriptpubkey_address:e.scriptpubkey_address,value:e.value??0}))):null}catch(e){if(clearTimeout(r),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);throw e}}};function M(e,t){if(0===e)return{termDurationDays:0,termLengthDays:30*t,isExpired:!1,daysUntilExpiry:30*t,daysIntoGracePeriod:0};const r=30*t,i=Math.floor(Date.now()/1e3)-e,a=Math.floor(i/86400);return{termDurationDays:a,termLengthDays:r,isExpired:a>r,daysUntilExpiry:Math.max(0,r-a),daysIntoGracePeriod:Math.max(0,a-r)}}function U(e,t,r,i){if(!e)return r??13e3;const a=i??o,n=Math.min(t,30);return o+n*n*(a-o)/900}function O(e,t,r){const i=e*t/10000000000000000n;if(0n===r)return{collateralValueUsd:i,collateralRatioBps:Number.MAX_SAFE_INTEGER};return{collateralValueUsd:i,collateralRatioBps:Number(i*n*10000n/r)}}function D(e){return e/100}var x=class e{constructor(t,r,i){if(r&&Array.isArray(r))this.sources=r;else{if(!Array.isArray(t))throw new Error("Price oracle requires a priceProviders array \u2014 defaults and fallbacks have been removed. Pass 3 distinct {name, apiKey[, apiSecret]} entries from the supported set: "+e.ACTIVE_PROVIDER_NAMES.join(", "));this.sources=this.buildSources(t)}this.sources.sort(((e,t)=>e.priority-t.priority)),this.validateProviderCount()}validateProviderCount(){if(this.sources.length<e.MIN_DISTINCT_PROVIDERS)throw new Error(`Price oracle requires at least ${e.MIN_DISTINCT_PROVIDERS} eligible providers for consensus. Currently configured: ${this.sources.length} provider(s). Supported active providers: ${e.ACTIVE_PROVIDER_NAMES.join(", ")}`)}buildSources(t){if(0===t.length)throw new Error("priceProviders must be a non-empty array of 3 distinct providers, each with an apiKey (Binance also requires apiSecret).");const r=[],i=new Set;let a=1;for(const o of t){if(!o||"string"!=typeof o.name)throw new Error("priceProviders entries must be {name, apiKey, apiSecret?} objects");const t=o.name.toLowerCase();if(!e.ACTIVE_PROVIDER_NAMES.includes(t))throw new Error(`Unsupported price provider "${o.name}". Supported: ${e.ACTIVE_PROVIDER_NAMES.join(", ")}`);if(i.has(t))throw new Error(`Duplicate price provider "${t}" \u2014 the oracle requires 3 DISTINCT providers so a single upstream failure or manipulation cannot compromise consensus. Use 3 different provider names from: ${e.ACTIVE_PROVIDER_NAMES.join(", ")}`);switch(i.add(t),t){case"binance":if(!o.apiKey||!o.apiSecret)throw new Error("Binance provider requires both apiKey and apiSecret");r.push(this.createBinanceSource(o.apiKey,o.apiSecret,a++));break;case"coinbase":if(!o.apiKey)throw new Error("Coinbase provider requires an apiKey");r.push(this.createCoinbaseSource(o.apiKey,a++));break;case"cryptocompare":if(!o.apiKey)throw new Error("CryptoCompare provider requires an apiKey");r.push(this.createCryptoCompareSource(o.apiKey,a++));break;case"coinmarketcap":if(!o.apiKey)throw new Error("CoinMarketCap provider requires an apiKey");r.push(this.createCoinMarketCapSource(o.apiKey,a++));break;case"coingecko":if(!o.apiKey)throw new Error("CoinGecko provider requires an apiKey (Demo or Pro). Unauthenticated CoinGecko access is not accepted \u2014 the free tier is rate-limited and edge-cached, which breaks median consensus under load.");r.push(this.createCoinGeckoSource(o.apiKey,a++));break;default:throw new Error(`Unhandled provider: ${t}`)}}if(r.length<e.MIN_DISTINCT_PROVIDERS)throw new Error(`Insufficient price providers: need at least ${e.MIN_DISTINCT_PROVIDERS} distinct entries, got ${r.length}.`);return this.selectSampledSources(r)}createCryptoCompareSource(e,t){return{name:"CryptoCompare",fetchPrice:async()=>{const t=new URL("https://min-api.cryptocompare.com/data/price");t.searchParams.set("fsym","BTC"),t.searchParams.set("tsyms","USDT"),t.searchParams.set("api_key",e);const r=await(async e=>{const t=new AbortController,r=setTimeout((()=>t.abort()),5e3);try{const i=await fetch(e,{signal:t.signal,headers:{Accept:"application/json"}});if(clearTimeout(r),!i.ok)throw new Error(`HTTP ${i.status} ${i.statusText}`);return await i.json()}catch(e){if(clearTimeout(r),"AbortError"===e.name)throw new Error("Request timeout after 5000ms");throw e}})(t.toString()),i=Number(r?.USDT);if(!Number.isFinite(i)||i<=0)throw new Error("Invalid CryptoCompare price payload");return i},priority:t}}createFetchJson(){return async(e,t)=>{const r=new AbortController,i=setTimeout((()=>r.abort()),5e3);try{const i=await fetch(e,{headers:{Accept:"application/json",...t||{}},signal:r.signal});if(!i.ok)throw new Error(`HTTP ${i.status} ${i.statusText}`);return await i.json()}finally{clearTimeout(i)}}}getSelectionSeed(){const e="undefined"!=typeof process?process.env.PRICE_PROVIDER_SELECTION_SEED:void 0,t=e?Number(e):NaN;return Number.isFinite(t)?t:("undefined"!=typeof process,0,Math.floor(Date.now()+1e6*Math.random()))}selectSampledSources(e){const t=[...e];let r=this.getSelectionSeed()>>>0;for(let e=t.length-1;e>0;e--){const i=Math.floor((r=1664525*r+1013904223>>>0,r/4294967296*(e+1)));[t[e],t[i]]=[t[i],t[e]]}return t.slice(0,3).map(((e,t)=>({...e,priority:t+1})))}createCoinGeckoSource(e,t){if(!e)throw new Error("createCoinGeckoSource requires an apiKey");const r=this.createFetchJson();return{name:"CoinGecko",fetchPrice:async()=>{const t=e.startsWith("pro:"),i=t?e.slice(4):e,a=t?{"x-cg-pro-api-key":i}:{"x-cg-demo-api-key":i},o=new URL("https://api.coingecko.com/api/v3/simple/price");o.searchParams.set("ids","bitcoin"),o.searchParams.set("vs_currencies","usd");const n=await r(o.toString(),a),s=Number(n?.bitcoin?.usd);if(!Number.isFinite(s)||s<=0)throw new Error("Invalid CoinGecko price payload");return s},priority:t}}createBinanceSource(e,t,r){if(!e||!t)throw new Error("createBinanceSource requires apiKey and apiSecret");void t;const i=this.createFetchJson();return{name:"Binance",fetchPrice:async()=>{const t=new URL("https://api.binance.com/api/v3/ticker/price");t.searchParams.set("symbol","BTCUSDT");const r=await i(t.toString(),{"X-MBX-APIKEY":e}),a=Number(r?.price);if(!Number.isFinite(a)||a<=0)throw new Error("Invalid Binance price payload");return a},priority:r}}createCoinbaseSource(e,t){if(!e)throw new Error("createCoinbaseSource requires an apiKey");const r=this.createFetchJson();return{name:"Coinbase",fetchPrice:async()=>{const t=await r("https://api.coinbase.com/v2/prices/BTC-USDT/spot",{"CB-ACCESS-KEY":e}),i=Number(t?.data?.amount);if(!Number.isFinite(i)||i<=0)throw new Error("Invalid Coinbase price payload");return i},priority:t}}createCoinMarketCapSource(e,t){const r=this.createFetchJson();return{name:"CoinMarketCap",fetchPrice:async()=>{const t=new URL("https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest");t.searchParams.set("symbol","BTC"),t.searchParams.set("convert","USDT");const i=await r(t.toString(),{"X-CMC_PRO_API_KEY":e}),a=Number(i?.data?.BTC?.[0]?.quote?.USDT?.price??i?.data?.BTC?.quote?.USDT?.price);if(!Number.isFinite(a)||a<=0)throw new Error("Invalid CoinMarketCap price payload");return a},priority:t}}async getBTCPrice(){const e=Date.now();if(3!==this.sources.length)throw new Error(`Price oracle requires exactly 3 providers. Currently configured: ${this.sources.length}`);const t=new Promise(((e,t)=>{setTimeout((()=>{t(new Error("Price oracle global timeout after 8000ms"))}),8e3)})),r=Promise.all(this.sources.map((async e=>{const t=Date.now(),r=await e.fetchPrice();return console.log(`[Price Oracle] \u2705 [+${Date.now()-t}ms] ${e.name}: $${r.toLocaleString()}`),r}))),i=[...await Promise.race([r,t])].sort(((e,t)=>e-t)),a=i[1];if((i[2]-i[0])/i[0]>.01){const e=this.sources.map((e=>e.name)).join(", "),t=i.map((e=>`$${e.toLocaleString()}`)).join(", ");throw new Error(`Price consensus failed: prices not within 1% tolerance. Providers: [${e}]. Prices: [${t}]`)}const o=Math.round(100*a),n=1000000n*BigInt(o),s=Date.now()-e;return console.log(`[Price Oracle] Median price: $${a.toLocaleString()} \u2014 total time: ${s}ms`),console.log(`[Price Oracle] Price with 8 decimals: ${n}`),n}async getBTCPriceConsensus(){console.log("[Price Oracle] Fetching BTC price with consensus...");const e=(await Promise.allSettled(this.sources.map((async e=>{const t=await e.fetchPrice();return{source:e.name,price:t}})))).filter((e=>"fulfilled"===e.status)).map((e=>e.value));if(0===e.length)throw new Error("No price sources returned data");console.log(`[Price Oracle] Got prices from ${e.length}/${this.sources.length} sources:`),e.forEach((e=>{console.log(` ${e.source}: $${e.price.toLocaleString()}`)}));const t=e.map((e=>e.price));t.sort(((e,t)=>e-t));const r=t[Math.floor(t.length/2)],i=t[0],a=t[t.length-1]/i,o=e.filter((e=>Math.abs(e.price-r)/r<=.02));if(a>1.05&&o.length===e.length)throw new Error(`Price consensus failed: sources too dispersed (${(100*(a-1)).toFixed(1)}% spread)`);if(o.length<e.length){const t=e.filter((e=>!o.find((t=>t.source===e.source))));if(console.log(`[Price Oracle] \u26a0\ufe0f Detected ${t.length} outlier(s):`),t.forEach((e=>{const t=Math.abs(e.price-r)/r;console.log(` ${e.source}: $${e.price.toLocaleString()} (${(100*t).toFixed(1)}% deviation)`)})),o.length<2)throw new Error("Price consensus failed: insufficient valid sources after outlier removal");console.log(`[Price Oracle] \u2705 Outliers filtered, continuing with ${o.length} valid sources`);const i=o.map((e=>e.price));i.sort(((e,t)=>e-t));const a=i[Math.floor(i.length/2)];console.log(`[Price Oracle] \u2705 Consensus price (median): $${a.toLocaleString()}`);const n=Math.round(100*a);return 1000000n*BigInt(n)}console.log(`[Price Oracle] \u2705 Consensus price (median): $${r.toLocaleString()}`);const n=Math.round(100*r);return 1000000n*BigInt(n)}};x.ACTIVE_PROVIDER_NAMES=["cryptocompare","coinbase","binance","coinmarketcap","coingecko"],x.MIN_DISTINCT_PROVIDERS=3;var k=x;function q(){const e=Math.floor(Date.now()/1e3);return t=e,Math.floor(t/l)*l;var t}var R=class{constructor(e){this.config=e,this.bitcoinProvider=e.bitcoinProvider}async calculateBalance(e,t){const r=await this.bitcoinProvider.getBalance(t),i=await this.getAuthorizedSpendsFromContract(e),a=i.reduce(((e,t)=>e+t.satoshis),0n),o=r>a?r-a:0n;return{totalUTXOs:[],totalBalance:r,authorizedUTXOs:i,authorizedBalance:a,authorizedSpendsHash:this.computeAuthorizedSpendsHash(e,i),availableUTXOs:[],availableBalance:o,vaultAddress:t,positionId:e,timestamp:Date.now()}}async calculateTrustedBalance(e,t,r){if(r)return await this.calculateBalance(e,t);const i=this.config.minConfirmations||6,a=await this.bitcoinProvider.getUTXOSet(t,i),o=await this.getAuthorizedSpendsFromContract(e);for(const e of o){if(a.utxos.some((t=>t.txid===e.txid&&t.vout===e.vout)))throw new Error(`Authorized UTXO ${e.txid}:${e.vout} not yet spent. Transaction was authorized in smart contract but not signed and broadcasted to Bitcoin network. Complete the transaction by signing and broadcasting it.`)}const n=o.reduce(((e,t)=>e+t.satoshis),0n),s=a.utxos.filter((e=>!this.isUTXOAuthorized(e,o))),c=s.reduce(((e,t)=>e+t.satoshis),0n),l=this.computeAuthorizedSpendsHash(e,o);return{totalUTXOs:a.utxos,totalBalance:a.totalBalance,authorizedUTXOs:o,authorizedBalance:n,authorizedSpendsHash:l,availableUTXOs:s,availableBalance:c,vaultAddress:t,positionId:e,timestamp:Date.now()}}async getTrustedBalance(e,t){return(await this.calculateTrustedBalance(e,t)).availableBalance}async getAvailableUTXOs(e,t){return(await this.calculateTrustedBalance(e,t)).availableUTXOs}async isUTXOAvailable(e,t,r,i){return(await this.getAvailableUTXOs(e,t)).some((e=>e.txid===r&&e.vout===i))}isUTXOAuthorized(e,t){return t.some((t=>t.txid===e.txid&&t.vout===e.vout))}async getAuthorizedSpendsFromContract(e){const t=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`;let r;r=this.config.rpcUrl?this.config.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.config.chain});const i=new ethers.providers.StaticJsonRpcProvider({url:r,timeout:d},this.config.chainId),a=new ethers.Contract(this.config.contractAddress,[{inputs:[{internalType:"bytes32",name:"positionId",type:"bytes32"}],name:"getAuthorizedSpends",outputs:[{components:[{internalType:"string",name:"txid",type:"string"},{internalType:"uint32",name:"vout",type:"uint32"},{internalType:"uint256",name:"satoshis",type:"uint256"},{internalType:"string",name:"targetAddress",type:"string"},{internalType:"uint256",name:"targetAmount",type:"uint256"},{internalType:"uint256",name:"authorizedAt",type:"uint256"}],internalType:"struct LoanOperationsManager.AuthorizedSpend[]",name:"",type:"tuple[]"}],stateMutability:"view",type:"function"}],i);return(await a.getAuthorizedSpends(t)).map((t=>({txid:t.txid,vout:Number(t.vout),satoshis:BigInt(t.satoshis.toString()),positionId:e,targetAddress:t.targetAddress,targetAmount:BigInt(t.targetAmount.toString()),timestamp:Number(t.authorizedAt)})))}computeAuthorizedSpendsHash(e,t){const r=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`;if(0===t.length)return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","bytes32[]"],[r,[]]));const i=t.map((e=>{const t=ethers.utils.keccak256(ethers.utils.toUtf8Bytes(e.txid)),r=ethers.utils.keccak256(ethers.utils.toUtf8Bytes(e.targetAddress));return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","uint32","uint256","bytes32","uint256","uint256"],[t,e.vout,e.satoshis.toString(),r,e.targetAmount.toString(),e.timestamp]))}));return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","bytes32[]"],[r,i]))}};var L=class{constructor(e){this.termManagerAddress=e.termManagerAddress,this.loanOpsManagerAddress=e.loanOpsManagerAddress,this.liquidationManagerAddress=e.liquidationManagerAddress,this.chain=e.chain,this.chainId=e.chainId,this.rpcUrl=e.rpcUrl}async getLiquidationThreshold(){try{let e;e=this.rpcUrl?this.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.chain});const t=new ethers.providers.StaticJsonRpcProvider({url:e,timeout:d},{name:"any",chainId:this.chainId}),r=[{inputs:[],name:"liquidationThreshold",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"}],i=new ethers.Contract(this.loanOpsManagerAddress,r,t),a=await i.liquidationThreshold();return Number(a.toString())}catch(e){throw console.error("[ProtocolParameters] Error fetching liquidation threshold:",e.message),new Error(`Failed to fetch liquidation threshold: ${e.message}`)}}async getTermFees(e){try{let t;t=this.rpcUrl?this.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.chain});const r=new ethers.providers.StaticJsonRpcProvider({url:t,timeout:d},{name:"any",chainId:this.chainId}),i=[{inputs:[{internalType:"uint256",name:"_termMonths",type:"uint256"}],name:"getTermFees",outputs:[{internalType:"uint88",name:"originationFee",type:"uint88"},{internalType:"uint88",name:"extensionFee",type:"uint88"}],stateMutability:"view",type:"function"}],a=new ethers.Contract(this.termManagerAddress,i,r),o=await a.getTermFees(e);return{originationFeeBps:Number(o.originationFee?.toString?.()??o[0]?.toString?.()??o[0]),extensionFeeBps:Number(o.extensionFee?.toString?.()??o[1]?.toString?.()??o[1])}}catch(e){throw console.error("[ProtocolParameters] Error fetching term fees:",e.message),new Error(`Failed to fetch term fees: ${e.message}`)}}async getAuthorizedSpendsHash(e){try{const t=this.rpcUrl||await Lit.Actions.getRpcUrl({chain:this.chain}),r=new ethers.providers.StaticJsonRpcProvider({url:t,timeout:d},{name:"any",chainId:this.chainId}),i=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`,a=new ethers.Contract(this.loanOpsManagerAddress,[{inputs:[{name:"positionId",type:"bytes32"}],name:"getAuthorizedSpendsHash",outputs:[{name:"",type:"bytes32"}],stateMutability:"view",type:"function"}],r);return await a.getAuthorizedSpendsHash(i)}catch(e){throw console.error("[ProtocolParameters] Error fetching authorized spends hash:",e.message),new Error(`Failed to fetch authorized spends hash: ${e.message}`)}}async getMaxEscalatedThreshold(){try{let e;e=this.rpcUrl?this.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.chain});const t=new ethers.providers.StaticJsonRpcProvider({url:e,timeout:d},{name:"any",chainId:this.chainId}),r=[{inputs:[],name:"maxEscalatedThreshold",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"}],i=new ethers.Contract(this.liquidationManagerAddress,r,t),a=await i.maxEscalatedThreshold();return Number(a.toString())}catch(e){throw console.error("[ProtocolParameters] Error fetching max escalated threshold:",e.message),new Error(`Failed to fetch max escalated threshold: ${e.message}`)}}};function N(e){return new L(e)}var F=class{constructor(e){this.config=e}async getVaultSnapshot(e){const t=await this.queryPositionState(e);console.log(`[Vault Snapshot] Raw vault address from contract: "${t.vaultAddress}"`);const r=!0===this.config.debugOverrides?.useStubbedBtcData,[i,a]=r?this.buildStubbedBtcSnapshotInputs(t):await Promise.all([this.config.vaultBalance.calculateTrustedBalance(e,t.vaultAddress),this.config.priceOracle.getBTCPriceConsensus()]),o=N({termManagerAddress:this.config.termManagerAddress,loanOpsManagerAddress:this.config.loanOpsManagerAddress,liquidationManagerAddress:this.config.liquidationManagerAddress,chain:this.config.chain,chainId:this.config.chainId||1,rpcUrl:this.config.rpcUrl}),n=this.config.termOverride??t.selectedTerm,[s,c,l]=await Promise.all([o.getLiquidationThreshold(),o.getMaxEscalatedThreshold(),o.getTermFees(n)]),u=M(t.termStartTimestamp,t.selectedTerm),d=U(u.isExpired,u.daysIntoGracePeriod,s,c),p=O(i.availableBalance,a,t.ucdDebt),h=p.collateralRatioBps<d,g=p.collateralRatioBps-d;return{positionId:t.positionId,pkpId:t.pkpId,borrower:t.borrower,vaultAddress:t.vaultAddress,ucdDebt:t.ucdDebt,termStartTimestamp:t.termStartTimestamp,selectedTerm:t.selectedTerm,status:t.status,expiryAt:t.expiryAt,previousExpiryAt:t.previousExpiryAt,totalTerm:t.totalTerm,totalBTCSats:i.totalBalance,totalUTXOs:i.totalUTXOs,authorizedSpendsSats:i.authorizedBalance,authorizedSpendsHash:i.authorizedSpendsHash,availableBTCSats:i.availableBalance,availableUTXOs:i.availableUTXOs,btcPriceUsd:a,collateralValueUsd:p.collateralValueUsd,collateralRatioBps:p.collateralRatioBps,termDurationDays:u.termDurationDays,termLengthDays:u.termLengthDays,isExpired:u.isExpired,daysUntilExpiry:u.daysUntilExpiry,daysIntoGracePeriod:u.daysIntoGracePeriod,currentLiquidationThreshold:d,isLiquidatable:h,marginToLiquidationBps:g,liquidationThresholdBps:s,originationFeeBps:l.originationFeeBps,extensionFeeBps:l.extensionFeeBps,timestamp:Date.now()}}async getVaultSnapshotFast(e){const t=await this.queryPositionState(e);console.log(`[Vault Snapshot] Raw vault address from contract: "${t.vaultAddress}"`);const r=!0===this.config.debugOverrides?.useStubbedBtcData,[i,a]=r?this.buildStubbedBtcSnapshotInputs(t):await Promise.all([this.config.vaultBalance.calculateTrustedBalance(e,t.vaultAddress,!0),this.config.priceOracle.getBTCPriceConsensus()]),o=N({termManagerAddress:this.config.termManagerAddress,loanOpsManagerAddress:this.config.loanOpsManagerAddress,liquidationManagerAddress:this.config.liquidationManagerAddress,chain:this.config.chain,chainId:this.config.chainId||1,rpcUrl:this.config.rpcUrl}),n=this.config.termOverride??t.selectedTerm,[s,c,l]=await Promise.all([o.getLiquidationThreshold(),o.getMaxEscalatedThreshold(),o.getTermFees(n)]),u=M(t.termStartTimestamp,t.selectedTerm),d=U(u.isExpired,u.daysIntoGracePeriod,s,c),p=O(i.availableBalance,a,t.ucdDebt),h=p.collateralRatioBps<d,g=p.collateralRatioBps-d;return{positionId:t.positionId,pkpId:t.pkpId,borrower:t.borrower,vaultAddress:t.vaultAddress,ucdDebt:t.ucdDebt,termStartTimestamp:t.termStartTimestamp,selectedTerm:t.selectedTerm,status:t.status,expiryAt:t.expiryAt,previousExpiryAt:t.previousExpiryAt,totalTerm:t.totalTerm,totalBTCSats:i.totalBalance,totalUTXOs:i.totalUTXOs,authorizedSpendsSats:i.authorizedBalance,authorizedSpendsHash:i.authorizedSpendsHash,availableBTCSats:i.availableBalance,availableUTXOs:i.availableUTXOs,btcPriceUsd:a,collateralValueUsd:p.collateralValueUsd,collateralRatioBps:p.collateralRatioBps,termDurationDays:u.termDurationDays,termLengthDays:u.termLengthDays,isExpired:u.isExpired,daysUntilExpiry:u.daysUntilExpiry,daysIntoGracePeriod:u.daysIntoGracePeriod,currentLiquidationThreshold:d,isLiquidatable:h,marginToLiquidationBps:g,liquidationThresholdBps:s,originationFeeBps:l.originationFeeBps,extensionFeeBps:l.extensionFeeBps,timestamp:Date.now()}}buildStubbedBtcSnapshotInputs(e){const t=BigInt(this.config.debugOverrides?.stubbedAvailableBtcSats??"10000000"),r=BigInt(this.config.debugOverrides?.stubbedBtcPriceUsd??"5000000000000");return[{totalUTXOs:[],totalBalance:t,authorizedUTXOs:[],authorizedBalance:0n,authorizedSpendsHash:this.config.debugOverrides?.stubbedAuthorizedSpendsHash??ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","bytes32[]"],[e.positionId,[]])),availableUTXOs:[],availableBalance:t,vaultAddress:e.vaultAddress,positionId:e.positionId,timestamp:Date.now()},r]}async queryPositionState(e){const t=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`;let r;r=this.config.rpcUrl?this.config.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.config.chain});const i=new ethers.providers.StaticJsonRpcProvider({url:r,timeout:d},this.config.chainId),a=new ethers.Contract(this.config.contractAddress,[{inputs:[],name:"core",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"}],i),o=await a.core(),n=new ethers.Contract(o,[{inputs:[{internalType:"bytes32",name:"positionId",type:"bytes32"}],name:"getPositionDetails",outputs:[{components:[{internalType:"bytes32",name:"positionId",type:"bytes32"},{internalType:"bytes32",name:"pkpId",type:"bytes32"},{internalType:"uint256",name:"ucdDebt",type:"uint256"},{internalType:"string",name:"vaultAddress",type:"string"},{internalType:"address",name:"borrower",type:"address"},{internalType:"uint40",name:"createdAt",type:"uint40"},{internalType:"uint40",name:"lastUpdated",type:"uint40"},{internalType:"uint16",name:"selectedTerm",type:"uint16"},{internalType:"uint40",name:"expiryAt",type:"uint40"},{internalType:"enum LoanStatusLib.LoanStatus",name:"status",type:"uint8"},{internalType:"uint40",name:"previousExpiryAt",type:"uint40"},{internalType:"uint16",name:"totalTerm",type:"uint16"}],internalType:"struct IPositionManagerCore.Position",name:"",type:"tuple"}],stateMutability:"view",type:"function"}],i),s=await n.getPositionDetails(t),c=Number(s.status);if(c<0||c>7)throw console.error("[VaultSnapshot] INVALID STATUS - ABI decoding error detected"),console.error(" Position ID:",t),console.error(" Contract:",this.config.contractAddress),console.error(" Status decoded:",c,"(expected 0-7)"),console.error(" Full position:",JSON.stringify(s,null,2)),new Error(`Invalid position status decoded from contract: ${c} (expected 0-7). This indicates an ABI decoding issue. Position: ${t}`);const l=Number(s.expiryAt),u=Number(s.selectedTerm),p=Number(s.totalTerm),h=Number(s.previousExpiryAt),g=(f=u,0===(m=l)?0:m-30*f*86400);var m,f;return{positionId:s.positionId,pkpId:s.pkpId,borrower:s.borrower,vaultAddress:this.parseVaultAddress(s.vaultAddress,T(this.config.chain)),ucdDebt:BigInt(s.ucdDebt.toString()),termStartTimestamp:g,selectedTerm:u,status:c,expiryAt:l,previousExpiryAt:h,totalTerm:p}}parseVaultAddress(e,t){try{const r=JSON.parse(e);if("object"==typeof r&&null!==r){if("sepolia"===t.toLowerCase())return r.regtest||r.testnet||r.mainnet;const e=function(e){return w[e]}(t);return"testnet"===e&&(r.testnet||r.regtest)||r.mainnet}}catch(e){}return e}async isLiquidatable(e){return(await this.getVaultSnapshot(e)).isLiquidatable}async getCollateralRatio(e){return(await this.getVaultSnapshot(e)).collateralRatioBps}async getAvailableBalance(e){return(await this.getVaultSnapshot(e)).availableBTCSats}async hasSufficientCollateral(e,t,r){const i=await this.getVaultSnapshot(e);return function(e,t,r,i){const a=t+r;return 0n===a||Number(e*n*10000n/a)>=i}(i.collateralValueUsd,i.ucdDebt,t,r)}};var _="function getProtocolPauseStatus() view returns (tuple(bool positionManagerPaused, bool positionManagerLiquidationsPaused, bool positionManagerCorePaused, bool loanOperationsPaused, bool collateralManagerPaused, bool liquidationManagerPaused, bool circuitBreakerPaused, bool ucdControllerPaused, bool ucdTokenPaused, bool simplePsmPaused))",V={mintUcd:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused","simplePsmPaused"],withdrawBtc:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","collateralManagerPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused","simplePsmPaused"],processPayment:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused"],extendPosition:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused","simplePsmPaused"],liquidation:["positionManagerLiquidationsPaused","liquidationManagerPaused","circuitBreakerPaused"],adminLiquidation:["positionManagerLiquidationsPaused","liquidationManagerPaused","circuitBreakerPaused"],btcTransactionSign:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","collateralManagerPaused","circuitBreakerPaused"]};function X(e){return{positionManagerPaused:e.positionManagerPaused,positionManagerLiquidationsPaused:e.positionManagerLiquidationsPaused,positionManagerCorePaused:e.positionManagerCorePaused,loanOperationsPaused:e.loanOperationsPaused,collateralManagerPaused:e.collateralManagerPaused,liquidationManagerPaused:e.liquidationManagerPaused,circuitBreakerPaused:e.circuitBreakerPaused,ucdControllerPaused:e.ucdControllerPaused,ucdTokenPaused:e.ucdTokenPaused,simplePsmPaused:e.simplePsmPaused}}var z=new ethers.utils.Interface(["function views() view returns (address)","function paused() view returns (bool)","function liquidationPaused() view returns (bool)","function simplePsm() view returns (address)"]),H=new ethers.utils.Interface(["function core() view returns (address)","function loanOps() view returns (address)","function collateralManager() view returns (address)","function liquidationManager() view returns (address)","function circuitBreaker() view returns (address)"]),j=new ethers.utils.Interface(["function getUcdController() view returns (address)","function ucdToken() view returns (address)"]),G=new ethers.utils.Interface(["function paused() view returns (bool)"]);async function K(e,t,r){return e.call({to:t,data:r})}async function J(e,t){const r=new ethers.utils.Interface([_]).encodeFunctionData("getProtocolPauseStatus",[]);let i;try{return function(e){const t=new ethers.utils.Interface([_]).decodeFunctionResult("getProtocolPauseStatus",e)[0];return Array.isArray(t)?X({positionManagerPaused:t[0],positionManagerLiquidationsPaused:t[1],positionManagerCorePaused:t[2],loanOperationsPaused:t[3],collateralManagerPaused:t[4],liquidationManagerPaused:t[5],circuitBreakerPaused:t[6],ucdControllerPaused:t[7],ucdTokenPaused:t[8],simplePsmPaused:t[9]}):X(t)}(await e.call({to:t,data:r}))}catch(e){i=e}try{return await async function(e,t){const r=await K(e,t,z.encodeFunctionData("views",[])),[i]=z.decodeFunctionResult("views",r),[a,o,n,s,c,l,u,d]=await Promise.all([K(e,t,z.encodeFunctionData("paused",[])),K(e,t,z.encodeFunctionData("liquidationPaused",[])),K(e,t,z.encodeFunctionData("simplePsm",[])),K(e,i,H.encodeFunctionData("core",[])),K(e,i,H.encodeFunctionData("loanOps",[])),K(e,i,H.encodeFunctionData("collateralManager",[])),K(e,i,H.encodeFunctionData("liquidationManager",[])),K(e,i,H.encodeFunctionData("circuitBreaker",[]))]),p=z.decodeFunctionResult("paused",a)[0],h=z.decodeFunctionResult("liquidationPaused",o)[0],g=z.decodeFunctionResult("simplePsm",n)[0],m=H.decodeFunctionResult("core",s)[0],f=H.decodeFunctionResult("loanOps",c)[0],w=H.decodeFunctionResult("collateralManager",l)[0],y=H.decodeFunctionResult("liquidationManager",u)[0],b=H.decodeFunctionResult("circuitBreaker",d)[0],T=await K(e,f,j.encodeFunctionData("getUcdController",[])),P=await K(e,f,j.encodeFunctionData("ucdToken",[])),v=j.decodeFunctionResult("getUcdController",T)[0],S=j.decodeFunctionResult("ucdToken",P)[0],E=async t=>{if(!t||t===ethers.constants.AddressZero)return!1;try{const r=await K(e,t,G.encodeFunctionData("paused",[]));return G.decodeFunctionResult("paused",r)[0]}catch{return!1}},[A,I,$,C,B,M,U,O]=await Promise.all([E(m),E(f),E(w),E(y),E(b),E(v),E(S),E(g)]);return X({positionManagerPaused:p,positionManagerLiquidationsPaused:h,positionManagerCorePaused:A,loanOperationsPaused:I,collateralManagerPaused:$,liquidationManagerPaused:C,circuitBreakerPaused:B,ucdControllerPaused:M,ucdTokenPaused:U,simplePsmPaused:O})}(e,t)}catch(e){const t=i instanceof Error?i.message:String(i),r=e instanceof Error?e.message:String(e);throw new Error(`getProtocolPauseStatus failed (aggregate: ${t}; decomposed: ${r})`)}}var W={hardhat:{chain:"hardhat",chainId:b.hardhat,bitcoinNetwork:w.hardhat,allowArbitraryBitcoinProvider:!0,allowArbitraryEvmRpc:!0,minBitcoinConfirmations:1},sepolia:{chain:"sepolia",chainId:b.sepolia,bitcoinNetwork:w.sepolia,allowArbitraryBitcoinProvider:!1,allowArbitraryEvmRpc:!1,minBitcoinConfirmations:1},ethereum:{chain:"ethereum",chainId:b.ethereum,bitcoinNetwork:w.ethereum,allowArbitraryBitcoinProvider:!1,allowArbitraryEvmRpc:!1,minBitcoinConfirmations:6}};var Y=[{inputs:[{internalType:"uint256",name:"chainId",type:"uint256"}],name:"getProviders",outputs:[{internalType:"bytes32[]",name:"ids",type:"bytes32[]"},{components:[{internalType:"bytes",name:"ciphertext",type:"bytes"},{internalType:"bytes32",name:"pkpId",type:"bytes32"},{internalType:"uint64",name:"addedAt",type:"uint64"}],internalType:"struct BitcoinProviderRegistry.ProviderEntry[]",name:"entries",type:"tuple[]"}],stateMutability:"view",type:"function"}];async function Q(e,t){const r=66===t.length?"0x"+t.slice(-40):t;try{const t=await Lit.Actions.Decrypt({pkpId:r,ciphertext:e}),i="string"==typeof t?t:String(t??"");if(!i)throw new Error("Decrypt returned empty plaintext");return i}catch(e){throw new Error(`Failed to decrypt Bitcoin provider URL (pkpId=${t}): ${e?.message??String(e)}`)}}async function Z(e){const{policy:t,bitcoinProviderUrl:r,ethersProvider:i,registryAddress:a}=e;if(!r||"string"!=typeof r)throw new Error("resolveBitcoinProviderForPolicy: bitcoinProviderUrl is required");if(t.allowArbitraryBitcoinProvider)return{name:"Custom Provider",url:r,minConfirmations:t.minBitcoinConfirmations,network:t.bitcoinNetwork};if(!a)throw new Error(`Bitcoin provider registry address is required on chain "${t.chain}" \u2014 set contractAddresses.BitcoinProviderRegistry. Hardcoded allowlists have been removed (see audit C-1/H-6 fix).`);const o=await async function(e,t,r){if(!r||"string"!=typeof r)throw new Error("fetchBitcoinProviderEntries: registryAddress (BitcoinProviderRegistry) is required");if(!t)throw new Error("fetchBitcoinProviderEntries: ethers provider is required");const i=new ethers.Contract(r,Y,t),[a,o]=await i.getProviders(e),n=[];for(let e=0;e<a.length;e++)n.push({providerId:a[e],ciphertext:o[e].ciphertext,pkpId:o[e].pkpId,addedAt:Number(o[e].addedAt)});return n}(t.chainId,i,a);if(0===o.length)throw new Error(`No Bitcoin providers registered for chainId=${t.chainId} in ${a}. Admin must addProvider(...) via AdminModule before LIT Actions can sign.`);const n=await async function(e,t){if(!t)throw new Error("matchAllowedProviderUrl: candidateUrl is required");for(const r of e)if(await Q(r.ciphertext,r.pkpId)===t)return r.providerId;return null}(o,r);if(!n)throw new Error(`Bitcoin provider URL not in any registered encrypted slot for chainId=${t.chainId}`);return{name:`Registry Provider ${n.slice(0,10)}`,url:r,minConfirmations:t.minBitcoinConfirmations,network:t.bitcoinNetwork}}var ee,te=[{inputs:[{internalType:"bytes32",name:"positionId",type:"bytes32"},{internalType:"uint256",name:"btcPrice",type:"uint256"},{internalType:"uint256",name:"quantumTimestamp",type:"uint256"},{internalType:"bytes",name:"liquidationValidatorSignature",type:"bytes"}],name:"isLiquidatable",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function"}];async function main(e){for(const[t,r]of Object.entries(e))globalThis[t]=r;console.log("[Admin Liquidation Validator] ========================================"),console.log("[Admin Liquidation Validator] DEBUG: Received globalThis parameters:"),console.log("[Admin Liquidation Validator] globalThis.contractAddresses:",globalThis.contractAddresses),console.log("[Admin Liquidation Validator] globalThis.positionId:",globalThis.positionId),console.log("[Admin Liquidation Validator] ========================================");let t,r,i,a,o,n="0";try{n="0a",console.log("[Step 0a] Validating configuration...");const e=globalThis.chain,d=globalThis.bitcoinProviderUrl,f=globalThis.positionId;if(!e)throw new Error('Missing required parameter: "chain"');if(!d)throw new Error('Missing required parameter: "bitcoinProviderUrl"');if(!f)throw new Error('Missing required parameter: "positionId"');n="0b";const w=function(e){const t=T(e),r=W[t];if(!r)throw new Error(`No chain policy registered for "${e}"`);return r}(e),b=w.chain;n="0c";const v=globalThis.contractAddresses;if(!v||"object"!=typeof v)throw new Error("Missing or invalid 'contractAddresses' parameter");if(r=v.PositionManager,i=v.LoanOperationsManagerModule,a=v.LiquidationManagerModule??v.LiquidationManager??"",o=v.BTCSpendAuthorizer||i,!r||!i||!a)throw new Error("Missing one or more required contract addresses (PositionManager, LoanOperationsManagerModule, LiquidationManager or LiquidationManagerModule)");let S;globalThis.rpcUrl&&"string"==typeof globalThis.rpcUrl?(!function(e,t){if(e.allowArbitraryEvmRpc)return;if(!t||"string"!=typeof t)throw new Error("validateEvmRpcForPolicy: rpcUrl must be a non-empty string");let r;try{r=new URL(t).hostname}catch(e){throw new Error(`Invalid rpcUrl: ${e?.message??String(e)}`)}if(!y.some((e=>r===e||r.endsWith(`.${e}`))))throw new Error(`Custom RPC domain "${r}" is not in the approved list: ${y.join(", ")}`)}(w,globalThis.rpcUrl),S=globalThis.rpcUrl):S=await Lit.Actions.getRpcUrl({chain:e}),t=new ethers.providers.JsonRpcProvider(S);const E=await Z({policy:w,bitcoinProviderUrl:d,ethersProvider:t,registryAddress:v.BitcoinProviderRegistry});console.log(` \u2705 Bitcoin Provider: ${E.name} (min confs ${E.minConfirmations})`);!function(e,t){const r=V[e],i=[];for(const e of r)t[e]&&i.push(e);if(i.length>0)throw new Error(JSON.stringify({code:"PROTOCOL_PAUSED",operation:e,paused:i,status:t}))}("adminLiquidation",await J(t,r));const A=new k(globalThis.priceProviders),I=new B({providerUrl:E.url}),$=(l={contractAddress:o,chain:e,chainId:w.chainId,rpcUrl:globalThis.rpcUrl,bitcoinProvider:I,minConfirmations:E.minConfirmations},new R(l)),C=function(e){return new F(e)}({contractAddress:r,termManagerAddress:v.TermManagerModule,loanOpsManagerAddress:i,liquidationManagerAddress:a,chain:e,chainId:P(b),rpcUrl:globalThis.rpcUrl,vaultBalance:$,priceOracle:A});n="1",console.log("[Step 1] Getting vault snapshot...");const M=await C.getVaultSnapshot(f);if(M.btcPriceUsd<s||M.btcPriceUsd>c)throw new Error(`Bitcoin price ${M.btcPriceUsd} is outside acceptable range (${s} - ${c}). This may indicate oracle manipulation or stale price data. Please try again later.`);console.log(` \u2705 BTC price validation passed: $${(Number(M.btcPriceUsd)/1e8).toFixed(2)}`),n="2",console.log("[Step 2] Validating position state...");const U=["ACTIVE","EXPIRED","LIQUIDATABLE"],O=p(M.status);if(!U.includes(O))throw new Error(`Invalid position status for liquidation: ${O}. Must be ACTIVE, EXPIRED, or LIQUIDATABLE.`);if(console.log(` \u2705 Position status valid for liquidation: ${p(M.status)}`),n="3",console.log("[Step 3] Checking liquidation eligibility..."),!M.isLiquidatable)throw new Error(`Position is not liquidatable (${D(M.collateralRatioBps)}% >= ${D(M.currentLiquidationThreshold)}%) - liquidation rejected.`);console.log(" \u2705 Position is liquidatable"),console.log(` - Current ratio: ${D(M.collateralRatioBps)}%`),console.log(` - Liquidation threshold: ${D(M.currentLiquidationThreshold)}%`),n="4",console.log("[Step 4] Building admin liquidation EIP-712 digest...");const x=q()+u,L=P(b),N=ethers.utils.keccak256(ethers.utils.toUtf8Bytes(m)),_={name:h,version:g,chainId:L,verifyingContract:ethers.utils.getAddress(a)},X={AdminLiquidationAuth:[{name:"actionTag",type:"bytes32"},{name:"positionId",type:"bytes32"},{name:"quantumTimestamp",type:"uint256"},{name:"btcPrice",type:"uint256"},{name:"btcVaultBalance",type:"uint256"}]},z={actionTag:N,positionId:f,quantumTimestamp:x,btcPrice:M.btcPriceUsd.toString(),btcVaultBalance:M.availableBTCSats.toString()};globalThis.publicKey;n="5",console.log("[Step 5] Signing authorization...");const H=globalThis.validatorWalletAddress;if(!H||!H.startsWith("0x"))throw new Error("validatorWalletAddress required \u2014 must be a createWallet-derived address");const j=await Lit.Actions.getPrivateKey({pkpId:H}),G="string"==typeof j?j.startsWith("0x")?j:`0x${j}`:String(j),K=new ethers.Wallet(G),Y=await K._signTypedData(_,X,z);let Q=null;if(globalThis.callIsLiquidatable&&a){n="6",console.log("[Step 6] Calling isLiquidatable() on contract...");try{new ethers.Contract(a,te,t);console.log(" \u26a0\ufe0f Skipping on-chain isLiquidatable() call (circular dependency with signature)"),console.log(" \u2139\ufe0f On-chain validation will occur in PositionManager.liquidatePosition()")}catch(e){console.warn(` \u26a0\ufe0f Failed to call isLiquidatable(): ${e.message}`)}}return console.log("[Admin Liquidation Validator] \u2705 Complete"),{approved:!0,positionId:f,btcPrice:M.btcPriceUsd.toString(),btcAmountSats:M.availableBTCSats.toString(),signature:Y,timestamp:x,validatorPkp:K.address,isLiquidatable:M.isLiquidatable,isLiquidatableOnChain:Q}}catch(e){return console.error("[Admin Liquidation Validator] \u274c Failed:",e.message),console.error(`[Admin Liquidation Validator] Failed at step: ${n}`),{approved:!1,reason:e.message||e.toString(),positionId:globalThis.positionId,timestamp:Date.now()}}var l}return ee=a,((a,o,n,s)=>{if(o&&"object"==typeof o||"function"==typeof o)for(let c of r(o))i.call(a,c)||c===n||e(a,c,{get:()=>o[c],enumerable:!(s=t(o,c))||s.enumerable});return a})(e({},"__esModule",{value:!0}),ee)})();if("object"==typeof _LIT_ACTION_)if("function"==typeof _LIT_ACTION_.main)var main=_LIT_ACTION_.main;else"function"==typeof _LIT_ACTION_.go&&_LIT_ACTION_.go();
|
|
1
|
+
var _LIT_ACTION_=(()=>{var e=Object.defineProperty,t=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.prototype.hasOwnProperty,a={};((t,r)=>{for(var i in r)e(t,i,{get:r[i],enumerable:!0})})(a,{main:()=>main});var o=11e3,n=1000000000000000000n,s=1000000000000n,c=100000000000000n,l=100,u=10,d=8e3;function p(e){switch(e){case 0:return"PENDING_DEPOSIT";case 1:return"PENDING_MINT";case 2:return"ACTIVE";case 3:return"EXPIRED";case 4:return"LIQUIDATABLE";case 5:return"LIQUIDATED";case 6:return"REPAID";case 7:return"CLOSED";default:return`UNKNOWN(${e})`}}var h="DiamondHands.Protocol",g="1",m="admin-liquidation",f=(e=>(e.SEPOLIA="sepolia",e.ETHEREUM="ethereum",e.HARDHAT="hardhat",e))(f||{}),w={sepolia:"testnet",ethereum:"mainnet",hardhat:"regtest"},y=["infura.io","drpc.org"],b={ethereum:1,sepolia:11155111,hardhat:1337};function T(e){const t=e.toLowerCase().trim();if("sepolia"===t)return"sepolia";if("ethereum"===t||"mainnet"===t)return"ethereum";if("hardhat"===t)return"hardhat";throw new Error(`Unsupported EVM chain: "${e}". Supported chains: ${Object.values(f).join(", ")}`)}function P(e){return b[e]}function v(e){if(!0===e)return!0;if(!1===e)return!1;const t=globalThis;return!0===t.debugAction||(!0===t.LIT_ACTION_DEBUG||("true"===t.LIT_ACTION_DEBUG||function(){try{if("undefined"==typeof process||!process.env)return!1;const e=process.env.LIT_ACTION_DEBUG,t=process.env.DEBUG;return"1"===e||"true"===e||"1"===t||"true"===t}catch{return!1}}()))}function S(...e){v()&&console.log(...e)}var E=class{stepStart(e,t){}stepEnd(e,t){}log(e,t,...r){}warn(e,t){}error(e,t){}getElapsed(){return 0}getRemaining(){return 3e4}summary(){}getExecutionId(){return""}isDebugEnabled(){return!1}},A=class{constructor(e){this.stepStartTimes=new Map,this.stepDurations=new Map,this.TIMEOUT_MS=3e4,this.actionName=e,this.executionStartTime=Date.now();const t=Date.now(),r=Math.random().toString(36).substring(2,9);this.executionId=`exec_${t}_${r}`,this.logHeader()}logHeader(){console.log(`[${this.actionName}] ========================================`),console.log(`[${this.actionName}] Execution started`),console.log(`[${this.actionName}] Execution ID: ${this.executionId}`);void 0!==globalThis.litNodeContext?(console.log(`[${this.actionName}] Context: LIT Node`),console.log(`[${this.actionName}] Node: ${globalThis.litNodeContext?.nodeAddress||"unknown"}`)):console.log(`[${this.actionName}] Context: Browser/Test`),console.log(`[${this.actionName}] ========================================`)}stepStart(e,t){this.stepStartTimes.set(e,Date.now());const r=Date.now()-this.executionStartTime,i=this.TIMEOUT_MS-r;console.log(`[Step ${e}] ${t}...`),console.log(`[Step ${e}] Elapsed: ${r}ms | Remaining: ${i}ms`)}stepEnd(e,t=5e3){const r=this.stepStartTimes.get(e);if(!r)return console.warn(`[Step ${e}] \u26a0\ufe0f stepEnd called without matching stepStart`),void 0;const i=Date.now()-r;this.stepDurations.set(e,i),console.log(`[Step ${e}] Duration: ${i}ms`),i>t&&console.warn(`\u26a0\ufe0f [Step ${e}] Took ${i}ms (> ${t}ms threshold)`);const a=Date.now()-this.executionStartTime,o=this.TIMEOUT_MS-a;o<5e3&&console.warn(`\u26a0\ufe0f [Step ${e}] Time remaining: ${o}ms (approaching timeout)`)}log(e,t,...r){r.length>0?console.log(`[Step ${e}] ${t}`,...r):console.log(`[Step ${e}] ${t}`)}warn(e,t){console.warn(`\u26a0\ufe0f [Step ${e}] ${t}`)}error(e,t){console.error(`\u274c [Step ${e}] ${t}`)}getElapsed(){return Date.now()-this.executionStartTime}getRemaining(){return this.TIMEOUT_MS-this.getElapsed()}summary(){const e=Date.now()-this.executionStartTime,t=this.TIMEOUT_MS-e;if(console.log(`[${this.actionName}] ========================================`),console.log(`[${this.actionName}] Execution Summary`),console.log(`[${this.actionName}] Execution ID: ${this.executionId}`),console.log(`[${this.actionName}] Total time: ${(e/1e3).toFixed(2)}s`),console.log(`[${this.actionName}] Time remaining: ${t}ms`),this.stepDurations.size>0){console.log(`[${this.actionName}] Step breakdown:`);for(const[t,r]of this.stepDurations.entries()){const i=(r/e*100).toFixed(1);console.log(`[${this.actionName}] Step ${t}: ${r}ms (${i}%)`)}}e>2e4&&console.warn(`\u26a0\ufe0f [${this.actionName}] Slow execution: ${(e/1e3).toFixed(2)}s (${t}ms remaining)`),t<5e3&&console.warn(`\u26a0\ufe0f [${this.actionName}] CRITICAL: Only ${t}ms remaining before timeout!`),console.log(`[${this.actionName}] ========================================`)}getExecutionId(){return this.executionId}isDebugEnabled(){return!0}},I=class{static create(e="LIT Action",t){return v(t)?new A(e):new E}};function $(e){if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function C(e){return e instanceof Error&&"AbortError"===e.name}var B=class{constructor(e){this.config=e,this.timeout=e.timeout||15e3,this.logger=I.create("BitcoinDataProvider")}async getCurrentBlockHeight(){if(this.logger.stepStart("0","getCurrentBlockHeight"),this.config.rpcHelper){const e=await this.config.rpcHelper.getBlockCount();return this.logger.stepEnd("0"),e}const e=new AbortController,t=setTimeout((()=>e.abort()),this.timeout);try{const r=Date.now(),i=await fetch(`${this.config.providerUrl}/blocks/tip/height`,{signal:e.signal,headers:{Accept:"text/plain","User-Agent":"Mozilla/5.0 (compatible; DiamondHandsValidator/1.0)","ngrok-skip-browser-warning":"true"}});if(clearTimeout(t),S(`[BitcoinDataProvider] blocks/tip/height ${Date.now()-r}ms (timeout budget ${this.timeout}ms)`),!i.ok)throw new Error(`Failed to fetch block height: ${i.status} ${i.statusText}`);const a=await i.text();if(a.trim().startsWith("<!DOCTYPE")||a.trim().startsWith("<html"))throw new Error("Bitcoin RPC endpoint returned HTML instead of block height. URL may be pointing to web interface instead of API endpoint. Expected: plain text number, Got: HTML document. Check that URL ends with /api/esplora (not root /)");const o=parseInt(a.trim(),10);if(isNaN(o)){const e=a.length>200?a.substring(0,200)+"... (truncated)":a;throw new Error(`Invalid block height response: ${e}`)}return this.logger.stepEnd("0"),o}catch(e){if(clearTimeout(t),this.logger.stepEnd("0"),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);throw e}}async getUTXOs(e){this.logger.log("0",`Original address: "${e}"`);const t=this.stripNetworkPrefix(e);if(this.logger.log("0",`Cleaned address: "${t}"`),this.config.rpcHelper)return await this.fetchUTXOsFromRPC(t);try{return await this.fetchUTXOsFromProvider(this.config.providerUrl,t)}catch(e){if(this.logger.warn("0",`Primary provider failed: ${$(e)}`),this.config.fallbackProviders&&this.config.fallbackProviders.length>0){const e=[...this.config.fallbackProviders].sort(((e,t)=>e.priority-t.priority));for(const r of e)try{return this.logger.log("0",`Trying fallback: ${r.name} (${r.url})`),await this.fetchUTXOsFromProvider(r.url,t)}catch(e){this.logger.warn("0",`Fallback ${r.name} failed: ${$(e)}`);continue}}throw new Error(`Failed to fetch UTXOs: ${$(e)}`)}}stripNetworkPrefix(e){return e.replace(/^(REGTEST_|TESTNET_|MAINNET_)/,"")}async fetchUTXOsFromRPC(e){if(!this.config.rpcHelper)throw new Error("RPC helper not configured");const t=this.config.rpcWallet||"";return(await this.config.rpcHelper.listUnspent(t,e)).map((e=>({txid:e.txid,vout:e.vout,satoshis:BigInt(Math.round(1e8*e.amount)),confirmations:e.confirmations})))}parseBlockstreamUTXOs(e,t){if(!Array.isArray(e))throw new Error("Invalid Blockstream response format: expected an array");const r=e,i=[];for(const e of r){let r=0;e.status&&"object"==typeof e.status?e.status.confirmed&&(r=void 0!==e.status.block_height&&e.status.block_height>0?t-e.status.block_height+1:1):void 0!==e.confirmations&&(r=e.confirmations);const a=e.txid,o=void 0!==e.vout?e.vout:e.n,n=void 0!==e.value?e.value:e.satoshis;if(void 0===a||void 0===o||void 0===n)throw new Error("Invalid UTXO row: missing txid, vout/n, or value/satoshis");i.push({txid:a,vout:o,satoshis:BigInt(n),confirmations:r})}return i}async fetchUTXOsFromProvider(e,t){this.logger.stepStart("1","fetchUTXOsFromProvider");const r=`${e}/address/${t}/utxos`;this.logger.log("1",`Fetching UTXOs from ${r}`);const i=new AbortController,a=setTimeout((()=>i.abort()),this.timeout);try{const e=Date.now(),[o,n]=await Promise.all([this.getCurrentBlockHeight(),fetch(r,{signal:i.signal,headers:{Accept:"application/json","Content-Type":"application/json","User-Agent":"Mozilla/5.0 (compatible; DiamondHandsValidator/1.0)","ngrok-skip-browser-warning":"true"}})]);if(clearTimeout(a),S(`[BitcoinDataProvider] parallel(tipHeight + GET utxos) wall ${Date.now()-e}ms endpoint tail .../${t.slice(0,12)}.../utxos (timeout budget ${this.timeout}ms)`),this.logger.log("1",`Current block height: ${o}`),!n.ok)throw new Error(`Bitcoin provider error: ${n.status} ${n.statusText}`);const s=await n.text();if(s.trim().startsWith("<!DOCTYPE")||s.trim().startsWith("<html"))throw new Error("Bitcoin RPC endpoint returned HTML instead of JSON. URL may be pointing to web interface instead of API endpoint. Expected: JSON array of UTXOs, Got: HTML document. Check that URL ends with /api/esplora (not root /)");let c;try{c=JSON.parse(s)}catch(e){const t=s.length>200?s.substring(0,200)+"... (truncated)":s;throw new Error(`Failed to parse JSON response: ${$(e)}. Response: ${t}`)}this.logger.log("1",`Raw API Response: ${JSON.stringify(c,null,2)}`);const l=this.parseBlockstreamUTXOs(c,o);return this.logger.stepEnd("1"),l}catch(e){if(clearTimeout(a),this.logger.stepEnd("1"),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);throw e}}async getUTXOSet(e,t){let r=[],i=null;for(let t=1;t<=3;t++)try{this.logger.log("2",`UTXO query attempt ${t}/3...`),r=await this.getUTXOs(e),this.logger.log("2",`UTXO query succeeded on attempt ${t}`),i=null;break}catch(e){i=e instanceof Error?e:new Error($(e)),this.logger.error("2",`UTXO query failed on attempt ${t}: ${$(e)}`),t<3&&(this.logger.log("2","Waiting 500ms before retry..."),await new Promise((e=>setTimeout(e,500))))}if(i)throw new Error(`Failed to query UTXOs after 3 attempts: ${i.message}`);const a=r.reduce(((e,t)=>e+t.satoshis),0n),o=r.filter((e=>e.confirmations>=t)).reduce(((e,t)=>e+t.satoshis),0n),n=a-o;return{utxos:r,totalBalance:a,totalUTXOs:r.length,confirmedBalance:o,unconfirmedBalance:n}}async getBalance(e){const t=this.stripNetworkPrefix(e),r=`${this.config.providerUrl}/address/${t}`;this.logger.log("3",`Fetching balance from ${r}`);const i=new AbortController,a=setTimeout((()=>i.abort()),this.timeout);try{const e=Date.now(),t=await fetch(r,{signal:i.signal,headers:{Accept:"application/json","Content-Type":"application/json","User-Agent":"Mozilla/5.0 (compatible; DiamondHandsValidator/1.0)","ngrok-skip-browser-warning":"true"}});if(clearTimeout(a),S(`[BitcoinDataProvider] GET address chain_stats ${Date.now()-e}ms (timeout budget ${this.timeout}ms)`),!t.ok)throw new Error(`Bitcoin provider error: ${t.status} ${t.statusText}`);const o=await t.json();if(!o.chain_stats)throw new Error("Invalid response: missing chain_stats");const n=o.chain_stats.funded_txo_sum,s=o.chain_stats.spent_txo_sum;if(void 0===n||void 0===s)throw new Error(`Invalid response: missing required fields. funded_txo_sum: ${n}, spent_txo_sum: ${s}`);const c=BigInt(n-s);return this.logger.log("3",`Balance: ${c.toString()} sats`),this.logger.log("3",` - Funded: ${n} sats, Spent: ${s} sats`),c}catch(e){if(clearTimeout(a),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);const r=$(e);throw this.logger.log("3",`Balance fetch failed: ${r}`),new Error(`Failed to fetch Bitcoin balance for address ${t}: ${r}`)}}async getTransaction(e){if(this.config.rpcHelper)try{const t=this.config.rpcWallet||"",r=await this.config.rpcHelper.getTransaction(t,e);return{txid:r.txid,confirmations:r.confirmations||0}}catch(e){const t=$(e),r=null!==e&&"object"==typeof e&&"code"in e&&"number"==typeof e.code?e.code:void 0;if(t.includes("Invalid or non-wallet transaction")||-5===r)return null;throw e}const t=new AbortController,r=setTimeout((()=>t.abort()),this.timeout);try{const i=Date.now(),a=await fetch(`${this.config.providerUrl}/tx/${e}`,{signal:t.signal});if(clearTimeout(r),S(`[BitcoinDataProvider] GET tx/${e.slice(0,10)}\u2026 ${Date.now()-i}ms (timeout budget ${this.timeout}ms)`),!a.ok){if(404===a.status)return null;throw new Error(`Bitcoin provider error: ${a.status} ${a.statusText}`)}const o=await a.json();return o.status?{txid:o.txid??e,confirmations:o.status.confirmed&&o.status.block_height?1:0}:null}catch(e){if(clearTimeout(r),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);if($(e).includes("404"))return null;throw e}}async getTransactionOutputs(e){if(!this.config.providerUrl)return null;const t=new AbortController,r=setTimeout((()=>t.abort()),this.timeout);try{const i=await fetch(`${this.config.providerUrl}/tx/${e}`,{signal:t.signal});if(clearTimeout(r),!i.ok){if(404===i.status)return null;throw new Error(`Bitcoin provider error: ${i.status} ${i.statusText}`)}const a=await i.json();return a.vout&&Array.isArray(a.vout)?a.vout.map(((e,t)=>({index:t,scriptpubkey:e.scriptpubkey,scriptpubkey_address:e.scriptpubkey_address,value:e.value??0}))):null}catch(e){if(clearTimeout(r),C(e))throw new Error(`Request timeout after ${this.timeout}ms`);throw e}}};function M(e,t){if(0===e)return{termDurationDays:0,termLengthDays:30*t,isExpired:!1,daysUntilExpiry:30*t,daysIntoGracePeriod:0};const r=30*t,i=Math.floor(Date.now()/1e3)-e,a=Math.floor(i/86400);return{termDurationDays:a,termLengthDays:r,isExpired:a>r,daysUntilExpiry:Math.max(0,r-a),daysIntoGracePeriod:Math.max(0,a-r)}}function U(e,t,r,i){if(!e)return r??13e3;const a=i??o,n=Math.min(t,30);return o+n*n*(a-o)/900}function O(e,t,r){const i=e*t/10000000000000000n;if(0n===r)return{collateralValueUsd:i,collateralRatioBps:Number.MAX_SAFE_INTEGER};return{collateralValueUsd:i,collateralRatioBps:Number(i*n*10000n/r)}}function D(e){return e/100}var x=class e{constructor(t,r,i){if(r&&Array.isArray(r))this.sources=r;else{if(!Array.isArray(t))throw new Error("Price oracle requires a priceProviders array \u2014 defaults and fallbacks have been removed. Pass 3 distinct {name, apiKey} entries from the supported set: "+e.ACTIVE_PROVIDER_NAMES.join(", "));this.sources=this.buildSources(t)}this.sources.sort(((e,t)=>e.priority-t.priority)),this.validateProviderCount()}validateProviderCount(){if(this.sources.length<e.MIN_DISTINCT_PROVIDERS)throw new Error(`Price oracle requires at least ${e.MIN_DISTINCT_PROVIDERS} eligible providers for consensus. Currently configured: ${this.sources.length} provider(s). Supported active providers: ${e.ACTIVE_PROVIDER_NAMES.join(", ")}`)}buildSources(t){if(0===t.length)throw new Error("priceProviders must be a non-empty array of 3 distinct providers, each with an apiKey.");const r=[],i=new Set;let a=1;for(const o of t){if(!o||"string"!=typeof o.name)throw new Error("priceProviders entries must be {name, apiKey, apiSecret?} objects");const t=o.name.toLowerCase();if(!e.ACTIVE_PROVIDER_NAMES.includes(t))throw new Error(`Unsupported price provider "${o.name}". Supported: ${e.ACTIVE_PROVIDER_NAMES.join(", ")}`);if(i.has(t))throw new Error(`Duplicate price provider "${t}" \u2014 the oracle requires 3 DISTINCT providers so a single upstream failure or manipulation cannot compromise consensus. Use 3 different provider names from: ${e.ACTIVE_PROVIDER_NAMES.join(", ")}`);switch(i.add(t),t){case"binance":if(!o.apiKey)throw new Error("Binance provider requires an apiKey");r.push(this.createBinanceSource(o.apiKey,a++));break;case"coinbase":if(!o.apiKey)throw new Error("Coinbase provider requires an apiKey");r.push(this.createCoinbaseSource(o.apiKey,a++));break;case"cryptocompare":if(!o.apiKey)throw new Error("CryptoCompare provider requires an apiKey");r.push(this.createCryptoCompareSource(o.apiKey,a++));break;case"coinmarketcap":if(!o.apiKey)throw new Error("CoinMarketCap provider requires an apiKey");r.push(this.createCoinMarketCapSource(o.apiKey,a++));break;case"coingecko":if(!o.apiKey)throw new Error("CoinGecko provider requires an apiKey (Demo or Pro). Unauthenticated CoinGecko access is not accepted \u2014 the free tier is rate-limited and edge-cached, which breaks median consensus under load.");r.push(this.createCoinGeckoSource(o.apiKey,a++));break;default:throw new Error(`Unhandled provider: ${t}`)}}if(r.length<e.MIN_DISTINCT_PROVIDERS)throw new Error(`Insufficient price providers: need at least ${e.MIN_DISTINCT_PROVIDERS} distinct entries, got ${r.length}.`);return this.selectSampledSources(r)}createCryptoCompareSource(e,t){return{name:"CryptoCompare",fetchPrice:async()=>{const t=new URL("https://min-api.cryptocompare.com/data/price");t.searchParams.set("fsym","BTC"),t.searchParams.set("tsyms","USDT"),t.searchParams.set("api_key",e);const r=await(async e=>{const t=new AbortController,r=setTimeout((()=>t.abort()),5e3);try{const i=await fetch(e,{signal:t.signal,headers:{Accept:"application/json"}});if(clearTimeout(r),!i.ok)throw new Error(`HTTP ${i.status} ${i.statusText}`);return await i.json()}catch(e){if(clearTimeout(r),"AbortError"===e.name)throw new Error("Request timeout after 5000ms");throw e}})(t.toString()),i=Number(r?.USDT);if(!Number.isFinite(i)||i<=0)throw new Error("Invalid CryptoCompare price payload");return i},priority:t}}createFetchJson(){return async(e,t)=>{const r=new AbortController,i=setTimeout((()=>r.abort()),5e3);try{const i=await fetch(e,{headers:{Accept:"application/json",...t||{}},signal:r.signal});if(!i.ok)throw new Error(`HTTP ${i.status} ${i.statusText}`);return await i.json()}finally{clearTimeout(i)}}}getSelectionSeed(){const e="undefined"!=typeof process?process.env.PRICE_PROVIDER_SELECTION_SEED:void 0,t=e?Number(e):NaN;return Number.isFinite(t)?t:("undefined"!=typeof process,0,Math.floor(Date.now()+1e6*Math.random()))}selectSampledSources(e){const t=[...e];let r=this.getSelectionSeed()>>>0;for(let e=t.length-1;e>0;e--){const i=Math.floor((r=1664525*r+1013904223>>>0,r/4294967296*(e+1)));[t[e],t[i]]=[t[i],t[e]]}return t.slice(0,3).map(((e,t)=>({...e,priority:t+1})))}createCoinGeckoSource(e,t){if(!e)throw new Error("createCoinGeckoSource requires an apiKey");const r=this.createFetchJson();return{name:"CoinGecko",fetchPrice:async()=>{const t=e.startsWith("pro:"),i=t?e.slice(4):e,a=t?{"x-cg-pro-api-key":i}:{"x-cg-demo-api-key":i},o=new URL("https://api.coingecko.com/api/v3/simple/price");o.searchParams.set("ids","bitcoin"),o.searchParams.set("vs_currencies","usd");const n=await r(o.toString(),a),s=Number(n?.bitcoin?.usd);if(!Number.isFinite(s)||s<=0)throw new Error("Invalid CoinGecko price payload");return s},priority:t}}createBinanceSource(e,t){if(!e)throw new Error("createBinanceSource requires an apiKey");const r=this.createFetchJson();return{name:"Binance",fetchPrice:async()=>{const t=new URL("https://api.binance.com/api/v3/ticker/price");t.searchParams.set("symbol","BTCUSDT");const i=await r(t.toString(),{"X-MBX-APIKEY":e}),a=Number(i?.price);if(!Number.isFinite(a)||a<=0)throw new Error("Invalid Binance price payload");return a},priority:t}}createCoinbaseSource(e,t){if(!e)throw new Error("createCoinbaseSource requires an apiKey");const r=this.createFetchJson();return{name:"Coinbase",fetchPrice:async()=>{const t=await r("https://api.coinbase.com/v2/prices/BTC-USDT/spot",{"CB-ACCESS-KEY":e}),i=Number(t?.data?.amount);if(!Number.isFinite(i)||i<=0)throw new Error("Invalid Coinbase price payload");return i},priority:t}}createCoinMarketCapSource(e,t){const r=this.createFetchJson();return{name:"CoinMarketCap",fetchPrice:async()=>{const t=new URL("https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest");t.searchParams.set("symbol","BTC"),t.searchParams.set("convert","USDT");const i=await r(t.toString(),{"X-CMC_PRO_API_KEY":e}),a=Number(i?.data?.BTC?.[0]?.quote?.USDT?.price??i?.data?.BTC?.quote?.USDT?.price);if(!Number.isFinite(a)||a<=0)throw new Error("Invalid CoinMarketCap price payload");return a},priority:t}}async getBTCPrice(){const e=Date.now();if(3!==this.sources.length)throw new Error(`Price oracle requires exactly 3 providers. Currently configured: ${this.sources.length}`);const t=new Promise(((e,t)=>{setTimeout((()=>{t(new Error("Price oracle global timeout after 8000ms"))}),8e3)})),r=Promise.all(this.sources.map((async e=>{const t=Date.now(),r=await e.fetchPrice();return console.log(`[Price Oracle] \u2705 [+${Date.now()-t}ms] ${e.name}: $${r.toLocaleString()}`),r}))),i=[...await Promise.race([r,t])].sort(((e,t)=>e-t)),a=i[1];if((i[2]-i[0])/i[0]>.01){const e=this.sources.map((e=>e.name)).join(", "),t=i.map((e=>`$${e.toLocaleString()}`)).join(", ");throw new Error(`Price consensus failed: prices not within 1% tolerance. Providers: [${e}]. Prices: [${t}]`)}const o=Math.round(100*a),n=1000000n*BigInt(o),s=Date.now()-e;return console.log(`[Price Oracle] Median price: $${a.toLocaleString()} \u2014 total time: ${s}ms`),console.log(`[Price Oracle] Price with 8 decimals: ${n}`),n}async getBTCPriceConsensus(){console.log("[Price Oracle] Fetching BTC price with consensus...");const e=(await Promise.allSettled(this.sources.map((async e=>{const t=await e.fetchPrice();return{source:e.name,price:t}})))).filter((e=>"fulfilled"===e.status)).map((e=>e.value));if(0===e.length)throw new Error("No price sources returned data");console.log(`[Price Oracle] Got prices from ${e.length}/${this.sources.length} sources:`),e.forEach((e=>{console.log(` ${e.source}: $${e.price.toLocaleString()}`)}));const t=e.map((e=>e.price));t.sort(((e,t)=>e-t));const r=t[Math.floor(t.length/2)],i=t[0],a=t[t.length-1]/i,o=e.filter((e=>Math.abs(e.price-r)/r<=.02));if(a>1.05&&o.length===e.length)throw new Error(`Price consensus failed: sources too dispersed (${(100*(a-1)).toFixed(1)}% spread)`);if(o.length<e.length){const t=e.filter((e=>!o.find((t=>t.source===e.source))));if(console.log(`[Price Oracle] \u26a0\ufe0f Detected ${t.length} outlier(s):`),t.forEach((e=>{const t=Math.abs(e.price-r)/r;console.log(` ${e.source}: $${e.price.toLocaleString()} (${(100*t).toFixed(1)}% deviation)`)})),o.length<2)throw new Error("Price consensus failed: insufficient valid sources after outlier removal");console.log(`[Price Oracle] \u2705 Outliers filtered, continuing with ${o.length} valid sources`);const i=o.map((e=>e.price));i.sort(((e,t)=>e-t));const a=i[Math.floor(i.length/2)];console.log(`[Price Oracle] \u2705 Consensus price (median): $${a.toLocaleString()}`);const n=Math.round(100*a);return 1000000n*BigInt(n)}console.log(`[Price Oracle] \u2705 Consensus price (median): $${r.toLocaleString()}`);const n=Math.round(100*r);return 1000000n*BigInt(n)}};x.ACTIVE_PROVIDER_NAMES=["cryptocompare","coinbase","binance","coinmarketcap","coingecko"],x.MIN_DISTINCT_PROVIDERS=3;var k=x;function q(){const e=Math.floor(Date.now()/1e3);return t=e,Math.floor(t/l)*l;var t}var R=class{constructor(e){this.config=e,this.bitcoinProvider=e.bitcoinProvider}async calculateBalance(e,t){const r=await this.bitcoinProvider.getBalance(t),i=await this.getAuthorizedSpendsFromContract(e),a=i.reduce(((e,t)=>e+t.satoshis),0n),o=r>a?r-a:0n;return{totalUTXOs:[],totalBalance:r,authorizedUTXOs:i,authorizedBalance:a,authorizedSpendsHash:this.computeAuthorizedSpendsHash(e,i),availableUTXOs:[],availableBalance:o,vaultAddress:t,positionId:e,timestamp:Date.now()}}async calculateTrustedBalance(e,t,r){if(r)return await this.calculateBalance(e,t);const i=this.config.minConfirmations||6,a=await this.bitcoinProvider.getUTXOSet(t,i),o=await this.getAuthorizedSpendsFromContract(e);for(const e of o){if(a.utxos.some((t=>t.txid===e.txid&&t.vout===e.vout)))throw new Error(`Authorized UTXO ${e.txid}:${e.vout} not yet spent. Transaction was authorized in smart contract but not signed and broadcasted to Bitcoin network. Complete the transaction by signing and broadcasting it.`)}const n=o.reduce(((e,t)=>e+t.satoshis),0n),s=a.utxos.filter((e=>!this.isUTXOAuthorized(e,o))),c=s.reduce(((e,t)=>e+t.satoshis),0n),l=this.computeAuthorizedSpendsHash(e,o);return{totalUTXOs:a.utxos,totalBalance:a.totalBalance,authorizedUTXOs:o,authorizedBalance:n,authorizedSpendsHash:l,availableUTXOs:s,availableBalance:c,vaultAddress:t,positionId:e,timestamp:Date.now()}}async getTrustedBalance(e,t){return(await this.calculateTrustedBalance(e,t)).availableBalance}async getAvailableUTXOs(e,t){return(await this.calculateTrustedBalance(e,t)).availableUTXOs}async isUTXOAvailable(e,t,r,i){return(await this.getAvailableUTXOs(e,t)).some((e=>e.txid===r&&e.vout===i))}isUTXOAuthorized(e,t){return t.some((t=>t.txid===e.txid&&t.vout===e.vout))}async getAuthorizedSpendsFromContract(e){const t=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`;let r;r=this.config.rpcUrl?this.config.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.config.chain});const i=new ethers.providers.StaticJsonRpcProvider({url:r,timeout:d},this.config.chainId),a=new ethers.Contract(this.config.contractAddress,[{inputs:[{internalType:"bytes32",name:"positionId",type:"bytes32"}],name:"getAuthorizedSpends",outputs:[{components:[{internalType:"string",name:"txid",type:"string"},{internalType:"uint32",name:"vout",type:"uint32"},{internalType:"uint256",name:"satoshis",type:"uint256"},{internalType:"string",name:"targetAddress",type:"string"},{internalType:"uint256",name:"targetAmount",type:"uint256"},{internalType:"uint256",name:"authorizedAt",type:"uint256"}],internalType:"struct LoanOperationsManager.AuthorizedSpend[]",name:"",type:"tuple[]"}],stateMutability:"view",type:"function"}],i);return(await a.getAuthorizedSpends(t)).map((t=>({txid:t.txid,vout:Number(t.vout),satoshis:BigInt(t.satoshis.toString()),positionId:e,targetAddress:t.targetAddress,targetAmount:BigInt(t.targetAmount.toString()),timestamp:Number(t.authorizedAt)})))}computeAuthorizedSpendsHash(e,t){const r=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`;if(0===t.length)return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","bytes32[]"],[r,[]]));const i=t.map((e=>{const t=ethers.utils.keccak256(ethers.utils.toUtf8Bytes(e.txid)),r=ethers.utils.keccak256(ethers.utils.toUtf8Bytes(e.targetAddress));return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","uint32","uint256","bytes32","uint256","uint256"],[t,e.vout,e.satoshis.toString(),r,e.targetAmount.toString(),e.timestamp]))}));return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","bytes32[]"],[r,i]))}};var L=class{constructor(e){this.termManagerAddress=e.termManagerAddress,this.loanOpsManagerAddress=e.loanOpsManagerAddress,this.liquidationManagerAddress=e.liquidationManagerAddress,this.chain=e.chain,this.chainId=e.chainId,this.rpcUrl=e.rpcUrl}async getLiquidationThreshold(){try{let e;e=this.rpcUrl?this.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.chain});const t=new ethers.providers.StaticJsonRpcProvider({url:e,timeout:d},{name:"any",chainId:this.chainId}),r=[{inputs:[],name:"liquidationThreshold",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"}],i=new ethers.Contract(this.loanOpsManagerAddress,r,t),a=await i.liquidationThreshold();return Number(a.toString())}catch(e){throw console.error("[ProtocolParameters] Error fetching liquidation threshold:",e.message),new Error(`Failed to fetch liquidation threshold: ${e.message}`)}}async getTermFees(e){try{let t;t=this.rpcUrl?this.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.chain});const r=new ethers.providers.StaticJsonRpcProvider({url:t,timeout:d},{name:"any",chainId:this.chainId}),i=[{inputs:[{internalType:"uint256",name:"_termMonths",type:"uint256"}],name:"getTermFees",outputs:[{internalType:"uint88",name:"originationFee",type:"uint88"},{internalType:"uint88",name:"extensionFee",type:"uint88"}],stateMutability:"view",type:"function"}],a=new ethers.Contract(this.termManagerAddress,i,r),o=await a.getTermFees(e);return{originationFeeBps:Number(o.originationFee?.toString?.()??o[0]?.toString?.()??o[0]),extensionFeeBps:Number(o.extensionFee?.toString?.()??o[1]?.toString?.()??o[1])}}catch(e){throw console.error("[ProtocolParameters] Error fetching term fees:",e.message),new Error(`Failed to fetch term fees: ${e.message}`)}}async getAuthorizedSpendsHash(e){try{const t=this.rpcUrl||await Lit.Actions.getRpcUrl({chain:this.chain}),r=new ethers.providers.StaticJsonRpcProvider({url:t,timeout:d},{name:"any",chainId:this.chainId}),i=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`,a=new ethers.Contract(this.loanOpsManagerAddress,[{inputs:[{name:"positionId",type:"bytes32"}],name:"getAuthorizedSpendsHash",outputs:[{name:"",type:"bytes32"}],stateMutability:"view",type:"function"}],r);return await a.getAuthorizedSpendsHash(i)}catch(e){throw console.error("[ProtocolParameters] Error fetching authorized spends hash:",e.message),new Error(`Failed to fetch authorized spends hash: ${e.message}`)}}async getMaxEscalatedThreshold(){try{let e;e=this.rpcUrl?this.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.chain});const t=new ethers.providers.StaticJsonRpcProvider({url:e,timeout:d},{name:"any",chainId:this.chainId}),r=[{inputs:[],name:"maxEscalatedThreshold",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"}],i=new ethers.Contract(this.liquidationManagerAddress,r,t),a=await i.maxEscalatedThreshold();return Number(a.toString())}catch(e){throw console.error("[ProtocolParameters] Error fetching max escalated threshold:",e.message),new Error(`Failed to fetch max escalated threshold: ${e.message}`)}}};function N(e){return new L(e)}var F=class{constructor(e){this.config=e}async getVaultSnapshot(e){const t=await this.queryPositionState(e);console.log(`[Vault Snapshot] Raw vault address from contract: "${t.vaultAddress}"`);const r=!0===this.config.debugOverrides?.useStubbedBtcData,[i,a]=r?this.buildStubbedBtcSnapshotInputs(t):await Promise.all([this.config.vaultBalance.calculateTrustedBalance(e,t.vaultAddress),this.config.priceOracle.getBTCPriceConsensus()]),o=N({termManagerAddress:this.config.termManagerAddress,loanOpsManagerAddress:this.config.loanOpsManagerAddress,liquidationManagerAddress:this.config.liquidationManagerAddress,chain:this.config.chain,chainId:this.config.chainId||1,rpcUrl:this.config.rpcUrl}),n=this.config.termOverride??t.selectedTerm,[s,c,l]=await Promise.all([o.getLiquidationThreshold(),o.getMaxEscalatedThreshold(),o.getTermFees(n)]),u=M(t.termStartTimestamp,t.selectedTerm),d=U(u.isExpired,u.daysIntoGracePeriod,s,c),p=O(i.availableBalance,a,t.ucdDebt),h=p.collateralRatioBps<d,g=p.collateralRatioBps-d;return{positionId:t.positionId,pkpId:t.pkpId,borrower:t.borrower,vaultAddress:t.vaultAddress,ucdDebt:t.ucdDebt,termStartTimestamp:t.termStartTimestamp,selectedTerm:t.selectedTerm,status:t.status,expiryAt:t.expiryAt,previousExpiryAt:t.previousExpiryAt,totalTerm:t.totalTerm,totalBTCSats:i.totalBalance,totalUTXOs:i.totalUTXOs,authorizedSpendsSats:i.authorizedBalance,authorizedSpendsHash:i.authorizedSpendsHash,availableBTCSats:i.availableBalance,availableUTXOs:i.availableUTXOs,btcPriceUsd:a,collateralValueUsd:p.collateralValueUsd,collateralRatioBps:p.collateralRatioBps,termDurationDays:u.termDurationDays,termLengthDays:u.termLengthDays,isExpired:u.isExpired,daysUntilExpiry:u.daysUntilExpiry,daysIntoGracePeriod:u.daysIntoGracePeriod,currentLiquidationThreshold:d,isLiquidatable:h,marginToLiquidationBps:g,liquidationThresholdBps:s,originationFeeBps:l.originationFeeBps,extensionFeeBps:l.extensionFeeBps,timestamp:Date.now()}}async getVaultSnapshotFast(e){const t=await this.queryPositionState(e);console.log(`[Vault Snapshot] Raw vault address from contract: "${t.vaultAddress}"`);const r=!0===this.config.debugOverrides?.useStubbedBtcData,[i,a]=r?this.buildStubbedBtcSnapshotInputs(t):await Promise.all([this.config.vaultBalance.calculateTrustedBalance(e,t.vaultAddress,!0),this.config.priceOracle.getBTCPriceConsensus()]),o=N({termManagerAddress:this.config.termManagerAddress,loanOpsManagerAddress:this.config.loanOpsManagerAddress,liquidationManagerAddress:this.config.liquidationManagerAddress,chain:this.config.chain,chainId:this.config.chainId||1,rpcUrl:this.config.rpcUrl}),n=this.config.termOverride??t.selectedTerm,[s,c,l]=await Promise.all([o.getLiquidationThreshold(),o.getMaxEscalatedThreshold(),o.getTermFees(n)]),u=M(t.termStartTimestamp,t.selectedTerm),d=U(u.isExpired,u.daysIntoGracePeriod,s,c),p=O(i.availableBalance,a,t.ucdDebt),h=p.collateralRatioBps<d,g=p.collateralRatioBps-d;return{positionId:t.positionId,pkpId:t.pkpId,borrower:t.borrower,vaultAddress:t.vaultAddress,ucdDebt:t.ucdDebt,termStartTimestamp:t.termStartTimestamp,selectedTerm:t.selectedTerm,status:t.status,expiryAt:t.expiryAt,previousExpiryAt:t.previousExpiryAt,totalTerm:t.totalTerm,totalBTCSats:i.totalBalance,totalUTXOs:i.totalUTXOs,authorizedSpendsSats:i.authorizedBalance,authorizedSpendsHash:i.authorizedSpendsHash,availableBTCSats:i.availableBalance,availableUTXOs:i.availableUTXOs,btcPriceUsd:a,collateralValueUsd:p.collateralValueUsd,collateralRatioBps:p.collateralRatioBps,termDurationDays:u.termDurationDays,termLengthDays:u.termLengthDays,isExpired:u.isExpired,daysUntilExpiry:u.daysUntilExpiry,daysIntoGracePeriod:u.daysIntoGracePeriod,currentLiquidationThreshold:d,isLiquidatable:h,marginToLiquidationBps:g,liquidationThresholdBps:s,originationFeeBps:l.originationFeeBps,extensionFeeBps:l.extensionFeeBps,timestamp:Date.now()}}buildStubbedBtcSnapshotInputs(e){const t=BigInt(this.config.debugOverrides?.stubbedAvailableBtcSats??"10000000"),r=BigInt(this.config.debugOverrides?.stubbedBtcPriceUsd??"5000000000000");return[{totalUTXOs:[],totalBalance:t,authorizedUTXOs:[],authorizedBalance:0n,authorizedSpendsHash:this.config.debugOverrides?.stubbedAuthorizedSpendsHash??ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["bytes32","bytes32[]"],[e.positionId,[]])),availableUTXOs:[],availableBalance:t,vaultAddress:e.vaultAddress,positionId:e.positionId,timestamp:Date.now()},r]}async queryPositionState(e){const t=e.startsWith("0x")?e:`0x${e.padStart(64,"0")}`;let r;r=this.config.rpcUrl?this.config.rpcUrl:await Lit.Actions.getRpcUrl({chain:this.config.chain});const i=new ethers.providers.StaticJsonRpcProvider({url:r,timeout:d},this.config.chainId),a=new ethers.Contract(this.config.contractAddress,[{inputs:[],name:"core",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"}],i),o=await a.core(),n=new ethers.Contract(o,[{inputs:[{internalType:"bytes32",name:"positionId",type:"bytes32"}],name:"getPositionDetails",outputs:[{components:[{internalType:"bytes32",name:"positionId",type:"bytes32"},{internalType:"bytes32",name:"pkpId",type:"bytes32"},{internalType:"uint256",name:"ucdDebt",type:"uint256"},{internalType:"string",name:"vaultAddress",type:"string"},{internalType:"address",name:"borrower",type:"address"},{internalType:"uint40",name:"createdAt",type:"uint40"},{internalType:"uint40",name:"lastUpdated",type:"uint40"},{internalType:"uint16",name:"selectedTerm",type:"uint16"},{internalType:"uint40",name:"expiryAt",type:"uint40"},{internalType:"enum LoanStatusLib.LoanStatus",name:"status",type:"uint8"},{internalType:"uint40",name:"previousExpiryAt",type:"uint40"},{internalType:"uint16",name:"totalTerm",type:"uint16"}],internalType:"struct IPositionManagerCore.Position",name:"",type:"tuple"}],stateMutability:"view",type:"function"}],i),s=await n.getPositionDetails(t),c=Number(s.status);if(c<0||c>7)throw console.error("[VaultSnapshot] INVALID STATUS - ABI decoding error detected"),console.error(" Position ID:",t),console.error(" Contract:",this.config.contractAddress),console.error(" Status decoded:",c,"(expected 0-7)"),console.error(" Full position:",JSON.stringify(s,null,2)),new Error(`Invalid position status decoded from contract: ${c} (expected 0-7). This indicates an ABI decoding issue. Position: ${t}`);const l=Number(s.expiryAt),u=Number(s.selectedTerm),p=Number(s.totalTerm),h=Number(s.previousExpiryAt),g=(f=u,0===(m=l)?0:m-30*f*86400);var m,f;return{positionId:s.positionId,pkpId:s.pkpId,borrower:s.borrower,vaultAddress:this.parseVaultAddress(s.vaultAddress,T(this.config.chain)),ucdDebt:BigInt(s.ucdDebt.toString()),termStartTimestamp:g,selectedTerm:u,status:c,expiryAt:l,previousExpiryAt:h,totalTerm:p}}parseVaultAddress(e,t){try{const r=JSON.parse(e);if("object"==typeof r&&null!==r){if("sepolia"===t.toLowerCase())return r.regtest||r.testnet||r.mainnet;const e=function(e){return w[e]}(t);return"testnet"===e&&(r.testnet||r.regtest)||r.mainnet}}catch(e){}return e}async isLiquidatable(e){return(await this.getVaultSnapshot(e)).isLiquidatable}async getCollateralRatio(e){return(await this.getVaultSnapshot(e)).collateralRatioBps}async getAvailableBalance(e){return(await this.getVaultSnapshot(e)).availableBTCSats}async hasSufficientCollateral(e,t,r){const i=await this.getVaultSnapshot(e);return function(e,t,r,i){const a=t+r;return 0n===a||Number(e*n*10000n/a)>=i}(i.collateralValueUsd,i.ucdDebt,t,r)}};var _="function getProtocolPauseStatus() view returns (tuple(bool positionManagerPaused, bool positionManagerLiquidationsPaused, bool positionManagerCorePaused, bool loanOperationsPaused, bool collateralManagerPaused, bool liquidationManagerPaused, bool circuitBreakerPaused, bool ucdControllerPaused, bool ucdTokenPaused, bool simplePsmPaused))",V={mintUcd:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused","simplePsmPaused"],withdrawBtc:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","collateralManagerPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused","simplePsmPaused"],processPayment:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused"],extendPosition:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","circuitBreakerPaused","ucdControllerPaused","ucdTokenPaused","simplePsmPaused"],liquidation:["positionManagerLiquidationsPaused","liquidationManagerPaused","circuitBreakerPaused"],adminLiquidation:["positionManagerLiquidationsPaused","liquidationManagerPaused","circuitBreakerPaused"],btcTransactionSign:["positionManagerPaused","positionManagerCorePaused","loanOperationsPaused","collateralManagerPaused","circuitBreakerPaused"]};function X(e){return{positionManagerPaused:e.positionManagerPaused,positionManagerLiquidationsPaused:e.positionManagerLiquidationsPaused,positionManagerCorePaused:e.positionManagerCorePaused,loanOperationsPaused:e.loanOperationsPaused,collateralManagerPaused:e.collateralManagerPaused,liquidationManagerPaused:e.liquidationManagerPaused,circuitBreakerPaused:e.circuitBreakerPaused,ucdControllerPaused:e.ucdControllerPaused,ucdTokenPaused:e.ucdTokenPaused,simplePsmPaused:e.simplePsmPaused}}var z=new ethers.utils.Interface(["function views() view returns (address)","function paused() view returns (bool)","function liquidationPaused() view returns (bool)","function simplePsm() view returns (address)"]),H=new ethers.utils.Interface(["function core() view returns (address)","function loanOps() view returns (address)","function collateralManager() view returns (address)","function liquidationManager() view returns (address)","function circuitBreaker() view returns (address)"]),j=new ethers.utils.Interface(["function getUcdController() view returns (address)","function ucdToken() view returns (address)"]),G=new ethers.utils.Interface(["function paused() view returns (bool)"]);async function K(e,t,r){return e.call({to:t,data:r})}async function J(e,t){const r=new ethers.utils.Interface([_]).encodeFunctionData("getProtocolPauseStatus",[]);let i;try{return function(e){const t=new ethers.utils.Interface([_]).decodeFunctionResult("getProtocolPauseStatus",e)[0];return Array.isArray(t)?X({positionManagerPaused:t[0],positionManagerLiquidationsPaused:t[1],positionManagerCorePaused:t[2],loanOperationsPaused:t[3],collateralManagerPaused:t[4],liquidationManagerPaused:t[5],circuitBreakerPaused:t[6],ucdControllerPaused:t[7],ucdTokenPaused:t[8],simplePsmPaused:t[9]}):X(t)}(await e.call({to:t,data:r}))}catch(e){i=e}try{return await async function(e,t){const r=await K(e,t,z.encodeFunctionData("views",[])),[i]=z.decodeFunctionResult("views",r),[a,o,n,s,c,l,u,d]=await Promise.all([K(e,t,z.encodeFunctionData("paused",[])),K(e,t,z.encodeFunctionData("liquidationPaused",[])),K(e,t,z.encodeFunctionData("simplePsm",[])),K(e,i,H.encodeFunctionData("core",[])),K(e,i,H.encodeFunctionData("loanOps",[])),K(e,i,H.encodeFunctionData("collateralManager",[])),K(e,i,H.encodeFunctionData("liquidationManager",[])),K(e,i,H.encodeFunctionData("circuitBreaker",[]))]),p=z.decodeFunctionResult("paused",a)[0],h=z.decodeFunctionResult("liquidationPaused",o)[0],g=z.decodeFunctionResult("simplePsm",n)[0],m=H.decodeFunctionResult("core",s)[0],f=H.decodeFunctionResult("loanOps",c)[0],w=H.decodeFunctionResult("collateralManager",l)[0],y=H.decodeFunctionResult("liquidationManager",u)[0],b=H.decodeFunctionResult("circuitBreaker",d)[0],T=await K(e,f,j.encodeFunctionData("getUcdController",[])),P=await K(e,f,j.encodeFunctionData("ucdToken",[])),v=j.decodeFunctionResult("getUcdController",T)[0],S=j.decodeFunctionResult("ucdToken",P)[0],E=async t=>{if(!t||t===ethers.constants.AddressZero)return!1;try{const r=await K(e,t,G.encodeFunctionData("paused",[]));return G.decodeFunctionResult("paused",r)[0]}catch{return!1}},[A,I,$,C,B,M,U,O]=await Promise.all([E(m),E(f),E(w),E(y),E(b),E(v),E(S),E(g)]);return X({positionManagerPaused:p,positionManagerLiquidationsPaused:h,positionManagerCorePaused:A,loanOperationsPaused:I,collateralManagerPaused:$,liquidationManagerPaused:C,circuitBreakerPaused:B,ucdControllerPaused:M,ucdTokenPaused:U,simplePsmPaused:O})}(e,t)}catch(e){const t=i instanceof Error?i.message:String(i),r=e instanceof Error?e.message:String(e);throw new Error(`getProtocolPauseStatus failed (aggregate: ${t}; decomposed: ${r})`)}}var W={hardhat:{chain:"hardhat",chainId:b.hardhat,bitcoinNetwork:w.hardhat,allowArbitraryBitcoinProvider:!0,allowArbitraryEvmRpc:!0,minBitcoinConfirmations:1},sepolia:{chain:"sepolia",chainId:b.sepolia,bitcoinNetwork:w.sepolia,allowArbitraryBitcoinProvider:!1,allowArbitraryEvmRpc:!1,minBitcoinConfirmations:1},ethereum:{chain:"ethereum",chainId:b.ethereum,bitcoinNetwork:w.ethereum,allowArbitraryBitcoinProvider:!1,allowArbitraryEvmRpc:!1,minBitcoinConfirmations:6}};var Y=[{inputs:[{internalType:"uint256",name:"chainId",type:"uint256"}],name:"getProviders",outputs:[{internalType:"bytes32[]",name:"ids",type:"bytes32[]"},{components:[{internalType:"bytes",name:"ciphertext",type:"bytes"},{internalType:"bytes32",name:"pkpId",type:"bytes32"},{internalType:"uint64",name:"addedAt",type:"uint64"}],internalType:"struct BitcoinProviderRegistry.ProviderEntry[]",name:"entries",type:"tuple[]"}],stateMutability:"view",type:"function"}];async function Q(e,t){const r=66===t.length?"0x"+t.slice(-40):t;try{const t=await Lit.Actions.Decrypt({pkpId:r,ciphertext:e}),i="string"==typeof t?t:String(t??"");if(!i)throw new Error("Decrypt returned empty plaintext");return i}catch(e){throw new Error(`Failed to decrypt Bitcoin provider URL (pkpId=${t}): ${e?.message??String(e)}`)}}async function Z(e){const{policy:t,bitcoinProviderUrl:r,ethersProvider:i,registryAddress:a}=e;if(!r||"string"!=typeof r)throw new Error("resolveBitcoinProviderForPolicy: bitcoinProviderUrl is required");if(t.allowArbitraryBitcoinProvider)return{name:"Custom Provider",url:r,minConfirmations:t.minBitcoinConfirmations,network:t.bitcoinNetwork};if(!a)throw new Error(`Bitcoin provider registry address is required on chain "${t.chain}" \u2014 set contractAddresses.BitcoinProviderRegistry. Hardcoded allowlists have been removed (see audit C-1/H-6 fix).`);const o=await async function(e,t,r){if(!r||"string"!=typeof r)throw new Error("fetchBitcoinProviderEntries: registryAddress (BitcoinProviderRegistry) is required");if(!t)throw new Error("fetchBitcoinProviderEntries: ethers provider is required");const i=new ethers.Contract(r,Y,t),[a,o]=await i.getProviders(e),n=[];for(let e=0;e<a.length;e++)n.push({providerId:a[e],ciphertext:o[e].ciphertext,pkpId:o[e].pkpId,addedAt:Number(o[e].addedAt)});return n}(t.chainId,i,a);if(0===o.length)throw new Error(`No Bitcoin providers registered for chainId=${t.chainId} in ${a}. Admin must addProvider(...) via AdminModule before LIT Actions can sign.`);const n=await async function(e,t){if(!t)throw new Error("matchAllowedProviderUrl: candidateUrl is required");for(const r of e)if(await Q(r.ciphertext,r.pkpId)===t)return r.providerId;return null}(o,r);if(!n)throw new Error(`Bitcoin provider URL not in any registered encrypted slot for chainId=${t.chainId}`);return{name:`Registry Provider ${n.slice(0,10)}`,url:r,minConfirmations:t.minBitcoinConfirmations,network:t.bitcoinNetwork}}var ee,te=[{inputs:[{internalType:"bytes32",name:"positionId",type:"bytes32"},{internalType:"uint256",name:"btcPrice",type:"uint256"},{internalType:"uint256",name:"quantumTimestamp",type:"uint256"},{internalType:"bytes",name:"liquidationValidatorSignature",type:"bytes"}],name:"isLiquidatable",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function"}];async function main(e){for(const[t,r]of Object.entries(e))globalThis[t]=r;console.log("[Admin Liquidation Validator] ========================================"),console.log("[Admin Liquidation Validator] DEBUG: Received globalThis parameters:"),console.log("[Admin Liquidation Validator] globalThis.contractAddresses:",globalThis.contractAddresses),console.log("[Admin Liquidation Validator] globalThis.positionId:",globalThis.positionId),console.log("[Admin Liquidation Validator] ========================================");let t,r,i,a,o,n="0";try{n="0a",console.log("[Step 0a] Validating configuration...");const e=globalThis.chain,d=globalThis.bitcoinProviderUrl,f=globalThis.positionId;if(!e)throw new Error('Missing required parameter: "chain"');if(!d)throw new Error('Missing required parameter: "bitcoinProviderUrl"');if(!f)throw new Error('Missing required parameter: "positionId"');n="0b";const w=function(e){const t=T(e),r=W[t];if(!r)throw new Error(`No chain policy registered for "${e}"`);return r}(e),b=w.chain;n="0c";const v=globalThis.contractAddresses;if(!v||"object"!=typeof v)throw new Error("Missing or invalid 'contractAddresses' parameter");if(r=v.PositionManager,i=v.LoanOperationsManagerModule,a=v.LiquidationManagerModule??v.LiquidationManager??"",o=v.BTCSpendAuthorizer||i,!r||!i||!a)throw new Error("Missing one or more required contract addresses (PositionManager, LoanOperationsManagerModule, LiquidationManager or LiquidationManagerModule)");let S;globalThis.rpcUrl&&"string"==typeof globalThis.rpcUrl?(!function(e,t){if(e.allowArbitraryEvmRpc)return;if(!t||"string"!=typeof t)throw new Error("validateEvmRpcForPolicy: rpcUrl must be a non-empty string");let r;try{r=new URL(t).hostname}catch(e){throw new Error(`Invalid rpcUrl: ${e?.message??String(e)}`)}if(!y.some((e=>r===e||r.endsWith(`.${e}`))))throw new Error(`Custom RPC domain "${r}" is not in the approved list: ${y.join(", ")}`)}(w,globalThis.rpcUrl),S=globalThis.rpcUrl):S=await Lit.Actions.getRpcUrl({chain:e}),t=new ethers.providers.JsonRpcProvider(S);const E=await Z({policy:w,bitcoinProviderUrl:d,ethersProvider:t,registryAddress:v.BitcoinProviderRegistry});console.log(` \u2705 Bitcoin Provider: ${E.name} (min confs ${E.minConfirmations})`);!function(e,t){const r=V[e],i=[];for(const e of r)t[e]&&i.push(e);if(i.length>0)throw new Error(JSON.stringify({code:"PROTOCOL_PAUSED",operation:e,paused:i,status:t}))}("adminLiquidation",await J(t,r));const A=new k(globalThis.priceProviders),I=new B({providerUrl:E.url}),$=(l={contractAddress:o,chain:e,chainId:w.chainId,rpcUrl:globalThis.rpcUrl,bitcoinProvider:I,minConfirmations:E.minConfirmations},new R(l)),C=function(e){return new F(e)}({contractAddress:r,termManagerAddress:v.TermManagerModule,loanOpsManagerAddress:i,liquidationManagerAddress:a,chain:e,chainId:P(b),rpcUrl:globalThis.rpcUrl,vaultBalance:$,priceOracle:A});n="1",console.log("[Step 1] Getting vault snapshot...");const M=await C.getVaultSnapshot(f);if(M.btcPriceUsd<s||M.btcPriceUsd>c)throw new Error(`Bitcoin price ${M.btcPriceUsd} is outside acceptable range (${s} - ${c}). This may indicate oracle manipulation or stale price data. Please try again later.`);console.log(` \u2705 BTC price validation passed: $${(Number(M.btcPriceUsd)/1e8).toFixed(2)}`),n="2",console.log("[Step 2] Validating position state...");const U=["ACTIVE","EXPIRED","LIQUIDATABLE"],O=p(M.status);if(!U.includes(O))throw new Error(`Invalid position status for liquidation: ${O}. Must be ACTIVE, EXPIRED, or LIQUIDATABLE.`);if(console.log(` \u2705 Position status valid for liquidation: ${p(M.status)}`),n="3",console.log("[Step 3] Checking liquidation eligibility..."),!M.isLiquidatable)throw new Error(`Position is not liquidatable (${D(M.collateralRatioBps)}% >= ${D(M.currentLiquidationThreshold)}%) - liquidation rejected.`);console.log(" \u2705 Position is liquidatable"),console.log(` - Current ratio: ${D(M.collateralRatioBps)}%`),console.log(` - Liquidation threshold: ${D(M.currentLiquidationThreshold)}%`),n="4",console.log("[Step 4] Building admin liquidation EIP-712 digest...");const x=q()+u,L=P(b),N=ethers.utils.keccak256(ethers.utils.toUtf8Bytes(m)),_={name:h,version:g,chainId:L,verifyingContract:ethers.utils.getAddress(a)},X={AdminLiquidationAuth:[{name:"actionTag",type:"bytes32"},{name:"positionId",type:"bytes32"},{name:"quantumTimestamp",type:"uint256"},{name:"btcPrice",type:"uint256"},{name:"btcVaultBalance",type:"uint256"}]},z={actionTag:N,positionId:f,quantumTimestamp:x,btcPrice:M.btcPriceUsd.toString(),btcVaultBalance:M.availableBTCSats.toString()};globalThis.publicKey;n="5",console.log("[Step 5] Signing authorization...");const H=globalThis.validatorWalletAddress;if(!H||!H.startsWith("0x"))throw new Error("validatorWalletAddress required \u2014 must be a createWallet-derived address");const j=await Lit.Actions.getPrivateKey({pkpId:H}),G="string"==typeof j?j.startsWith("0x")?j:`0x${j}`:String(j),K=new ethers.Wallet(G),Y=await K._signTypedData(_,X,z);let Q=null;if(globalThis.callIsLiquidatable&&a){n="6",console.log("[Step 6] Calling isLiquidatable() on contract...");try{new ethers.Contract(a,te,t);console.log(" \u26a0\ufe0f Skipping on-chain isLiquidatable() call (circular dependency with signature)"),console.log(" \u2139\ufe0f On-chain validation will occur in PositionManager.liquidatePosition()")}catch(e){console.warn(` \u26a0\ufe0f Failed to call isLiquidatable(): ${e.message}`)}}return console.log("[Admin Liquidation Validator] \u2705 Complete"),{approved:!0,positionId:f,btcPrice:M.btcPriceUsd.toString(),btcAmountSats:M.availableBTCSats.toString(),signature:Y,timestamp:x,validatorPkp:K.address,isLiquidatable:M.isLiquidatable,isLiquidatableOnChain:Q}}catch(e){return console.error("[Admin Liquidation Validator] \u274c Failed:",e.message),console.error(`[Admin Liquidation Validator] Failed at step: ${n}`),{approved:!1,reason:e.message||e.toString(),positionId:globalThis.positionId,timestamp:Date.now()}}var l}return ee=a,((a,o,n,s)=>{if(o&&"object"==typeof o||"function"==typeof o)for(let c of r(o))i.call(a,c)||c===n||e(a,c,{get:()=>o[c],enumerable:!(s=t(o,c))||s.enumerable});return a})(e({},"__esModule",{value:!0}),ee)})();if("object"==typeof _LIT_ACTION_)if("function"==typeof _LIT_ACTION_.main)var main=_LIT_ACTION_.main;else"function"==typeof _LIT_ACTION_.go&&_LIT_ACTION_.go();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
8eb26b08623d6be2ded733579d61c389fe312eef8d12ae1e62166c9359bbd037
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"actionName": "admin-liquidation-validator",
|
|
3
|
-
"originalSize":
|
|
4
|
-
"minifiedSize":
|
|
5
|
-
"compressionRatio": 0.
|
|
6
|
-
"hash": "
|
|
7
|
-
"buildTime":
|
|
3
|
+
"originalSize": 118258,
|
|
4
|
+
"minifiedSize": 51556,
|
|
5
|
+
"compressionRatio": 0.564037950920868,
|
|
6
|
+
"hash": "8eb26b08623d6be2ded733579d61c389fe312eef8d12ae1e62166c9359bbd037",
|
|
7
|
+
"buildTime": 1777471360708,
|
|
8
8
|
"version": "0.1.0"
|
|
9
9
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"actionName": "btc-transaction-signer",
|
|
3
|
-
"originalSize":
|
|
4
|
-
"minifiedSize":
|
|
5
|
-
"compressionRatio": 0.
|
|
6
|
-
"hash": "
|
|
7
|
-
"buildTime":
|
|
3
|
+
"originalSize": 58487,
|
|
4
|
+
"minifiedSize": 25657,
|
|
5
|
+
"compressionRatio": 0.5613213192675295,
|
|
6
|
+
"hash": "422311d10447a806bf435a1df440ff00d4eee986c019ccdb4af15bdbfd8019cf",
|
|
7
|
+
"buildTime": 1777471360994,
|
|
8
8
|
"version": "0.1.0"
|
|
9
9
|
}
|