@babylonlabs-io/ts-sdk 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PayoutManager-9qwA76_B.cjs +2 -0
- package/dist/PayoutManager-9qwA76_B.cjs.map +1 -0
- package/dist/{PayoutManager-BVmU4UsM.js → PayoutManager-CvWBwdzd.js} +178 -204
- package/dist/PayoutManager-CvWBwdzd.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +72 -70
- package/dist/index.js.map +1 -1
- package/dist/shared/index.cjs +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +5 -3
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/wallets/__tests__/signOptions.test.d.ts +2 -0
- package/dist/shared/wallets/__tests__/signOptions.test.d.ts.map +1 -0
- package/dist/shared/wallets/index.d.ts +1 -0
- package/dist/shared/wallets/index.d.ts.map +1 -1
- package/dist/shared/wallets/signOptions.d.ts +15 -0
- package/dist/shared/wallets/signOptions.d.ts.map +1 -0
- package/dist/signOptions-Deg5lCoC.cjs +2 -0
- package/dist/signOptions-Deg5lCoC.cjs.map +1 -0
- package/dist/signOptions-Drwr3bXB.js +16 -0
- package/dist/signOptions-Drwr3bXB.js.map +1 -0
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +1 -1
- package/dist/tbv/core/managers/PayoutManager.d.ts +1 -1
- package/dist/tbv/core/managers/PayoutManager.d.ts.map +1 -1
- package/dist/tbv/core/managers/PeginManager.d.ts +1 -2
- package/dist/tbv/core/managers/PeginManager.d.ts.map +1 -1
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +1 -1
- package/dist/tbv/integrations/aave/clients/abis/{AaveIntegrationController.abi.json.d.ts → AaveIntegrationAdapter.abi.json.d.ts} +39 -2
- package/dist/tbv/integrations/aave/clients/index.d.ts +1 -1
- package/dist/tbv/integrations/aave/clients/index.d.ts.map +1 -1
- package/dist/tbv/integrations/aave/clients/query.d.ts +3 -3
- package/dist/tbv/integrations/aave/clients/transaction.d.ts +19 -7
- package/dist/tbv/integrations/aave/clients/transaction.d.ts.map +1 -1
- package/dist/tbv/integrations/aave/constants.d.ts +2 -0
- package/dist/tbv/integrations/aave/constants.d.ts.map +1 -1
- package/dist/tbv/integrations/aave/index.cjs +1 -1
- package/dist/tbv/integrations/aave/index.cjs.map +1 -1
- package/dist/tbv/integrations/aave/index.d.ts +6 -6
- package/dist/tbv/integrations/aave/index.d.ts.map +1 -1
- package/dist/tbv/integrations/aave/index.js +141 -94
- package/dist/tbv/integrations/aave/index.js.map +1 -1
- package/dist/tbv/integrations/aave/types.d.ts +1 -1
- package/dist/tbv/integrations/aave/utils/__tests__/seizureSimulation.test.d.ts +5 -0
- package/dist/tbv/integrations/aave/utils/__tests__/seizureSimulation.test.d.ts.map +1 -0
- package/dist/tbv/integrations/aave/utils/index.d.ts +2 -0
- package/dist/tbv/integrations/aave/utils/index.d.ts.map +1 -1
- package/dist/tbv/integrations/aave/utils/seizureSimulation.d.ts +109 -0
- package/dist/tbv/integrations/aave/utils/seizureSimulation.d.ts.map +1 -0
- package/dist/tbv/integrations/aave/utils/vaultSplit.d.ts +1 -0
- package/dist/tbv/integrations/aave/utils/vaultSplit.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/PayoutManager-BVmU4UsM.js.map +0 -1
- package/dist/PayoutManager-Ba6cNgHC.cjs +0 -2
- package/dist/PayoutManager-Ba6cNgHC.cjs.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var q=Object.defineProperty;var L=(n,t,e)=>t in n?q(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var C=(n,t,e)=>L(n,typeof t!="symbol"?t+"":t,e);const P=require("bitcoinjs-lib"),y=require("buffer"),u=require("./challengeAssert-DDceAi0r.cjs"),w=require("viem"),O=require("./signOptions-Deg5lCoC.cjs"),V=require("@babylonlabs-io/babylon-tbv-rust-wasm");function z(n){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const e in n)if(e!=="default"){const r=Object.getOwnPropertyDescriptor(n,e);Object.defineProperty(t,e,r.get?r:{enumerable:!0,get:()=>n[e]})}}return t.default=n,Object.freeze(t)}const j=z(P);function W(n,t,e){if(n.length===0)throw new Error("Insufficient funds: no UTXOs available");const r=n.filter(o=>{const l=y.Buffer.from(o.scriptPubKey,"hex");return!!P.script.decompile(l)});if(r.length===0)throw new Error("Insufficient funds: no valid UTXOs available (all have invalid scripts)");const a=[...r].sort((o,l)=>l.value-o.value),s=[];let c=0n,i=0n;for(const o of a){s.push(o),c+=BigInt(o.value);const l=s.length*u.P2TR_INPUT_SIZE,d=2*u.MAX_NON_LEGACY_OUTPUT_SIZE,h=l+d+u.TX_BUFFER_SIZE_OVERHEAD;if(i=BigInt(Math.ceil(h*e))+BigInt(u.rateBasedTxBufferFee(e)),c-t-i>u.DUST_THRESHOLD){const b=BigInt(Math.ceil(u.MAX_NON_LEGACY_OUTPUT_SIZE*e));i+=b}if(c>=t+i){const b=c-t-i;return{selectedUTXOs:s,totalValue:c,fee:i,changeAmount:b}}}throw new Error(`Insufficient funds: need ${t+i} sats (${t} pegin + ${i} fee), have ${c} sats`)}function G(n){return n>u.DUST_THRESHOLD}function Z(){return u.BTC_DUST_SAT}function U(n){const t=n.startsWith("0x")?n.slice(2):n;return`0x${P.Transaction.fromHex(t).getId()}`}function J(n,t,e){if(n.length===0)throw new Error("No input UTXOs provided for split transaction");if(t.length===0)throw new Error("No outputs specified for split transaction");for(const o of t)if(o.amount<=0n)throw new Error(`Invalid output amount for ${o.address}: ${o.amount} satoshis. Amount must be greater than zero.`);const r=u.getNetwork(e),a=new P.Transaction;a.version=2;for(const o of n){const l=y.Buffer.from(o.txid,"hex").reverse();a.addInput(l,o.vout)}const s=[];for(let o=0;o<t.length;o++){const l=t[o];let d;try{d=P.address.toOutputScript(l.address,r)}catch(h){throw new Error(`Failed to decode address "${l.address}": ${h instanceof Error?h.message:String(h)}`)}a.addOutput(d,Number(l.amount)),s.push({txid:"",vout:o,value:Number(l.amount),scriptPubKey:d.toString("hex")})}const c=a.toHex(),i=a.getId();for(const o of s)o.txid=i;return{txHex:c,txid:i,outputs:s}}function Y(n,t,e){const r=P.Transaction.fromHex(n),a=new P.Psbt;if(a.setVersion(r.version),a.setLocktime(r.locktime),!y.Buffer.isBuffer(e)||e.length!==32)throw new Error(`Invalid publicKeyNoCoord: expected 32-byte Buffer (x-only pubkey), got ${y.Buffer.isBuffer(e)?`${e.length}-byte Buffer`:typeof e}`);if(t.length!==r.ins.length)throw new Error(`UTXO count mismatch: transaction has ${r.ins.length} input${r.ins.length!==1?"s":""}, but ${t.length} UTXO${t.length!==1?"s were":" was"} provided`);for(let s=0;s<r.ins.length;s++){const c=r.ins[s],i=t[s];if(!i)throw new Error(`Missing UTXO data for input ${s}`);const o=y.Buffer.from(c.hash).reverse().toString("hex"),l=c.index;if(i.txid!==o||i.vout!==l)throw new Error(`Input ${s} outpoint mismatch: transaction expects ${o}:${l}, but UTXO ${i.txid}:${i.vout} was provided. Ensure inputs array matches the order used in createSplitTransaction().`);const d=y.Buffer.from(i.scriptPubKey,"hex");if(!(d.length===34&&d[0]===81&&d[1]===32))throw new Error(`Input ${s} must be P2TR (Taproot). createSplitTransactionPsbt() requires P2TR inputs because it uses tapInternalKey for Taproot signing. ScriptPubKey: ${i.scriptPubKey.substring(0,20)}...`);const g={script:y.Buffer.from(i.scriptPubKey,"hex"),value:i.value};a.addInput({hash:c.hash,index:c.index,sequence:c.sequence,witnessUtxo:g,tapInternalKey:e})}for(const s of r.outs)a.addOutput({script:s.script,value:s.value});return a.toHex()}var E=(n=>(n.P2PKH="P2PKH",n.P2SH="P2SH",n.P2WPKH="P2WPKH",n.P2WSH="P2WSH",n.P2TR="P2TR",n.UNKNOWN="UNKNOWN",n))(E||{});function N(n){const t=n.length;return t===25&&n[0]===118&&n[1]===169&&n[2]===20&&n[23]===136&&n[24]===172?"P2PKH":t===23&&n[0]===169&&n[1]===20&&n[22]===135?"P2SH":t===22&&n[0]===0&&n[1]===20?"P2WPKH":t===34&&n[0]===0&&n[1]===32?"P2WSH":t===34&&n[0]===81&&n[1]===32?"P2TR":"UNKNOWN"}function M(n,t){const e=y.Buffer.from(n.scriptPubKey,"hex"),r=N(e);switch(r){case E.P2WPKH:return{witnessUtxo:{script:e,value:n.value}};case E.P2WSH:{if(!n.witnessScript)throw new Error("Missing witnessScript for P2WSH input");return{witnessUtxo:{script:e,value:n.value},witnessScript:y.Buffer.from(n.witnessScript,"hex")}}case E.P2TR:{if(t&&t.length!==32)throw new Error(`Invalid tapInternalKey length: expected 32 bytes, got ${t.length}`);return{witnessUtxo:{script:e,value:n.value},...t&&{tapInternalKey:t}}}default:throw new Error(`Unsupported script type: ${r}`)}}const _={mainnet:"https://mempool.space/api",testnet:"https://mempool.space/testnet/api",signet:"https://mempool.space/signet/api"};async function H(n,t){try{const e=await fetch(n,t);if(!e.ok){const a=await e.text();throw new Error(`Mempool API error (${e.status}): ${a||e.statusText}`)}const r=e.headers.get("content-type");return r!=null&&r.includes("application/json")?await e.json():await e.text()}catch(e){throw e instanceof Error?new Error(`Failed to fetch from mempool API: ${e.message}`):new Error("Failed to fetch from mempool API: Unknown error")}}async function K(n,t){try{const e=await fetch(`${t}/tx`,{method:"POST",body:n,headers:{"Content-Type":"text/plain"}});if(!e.ok){const a=await e.text();let s;try{s=JSON.parse(a).message}catch{s=a}throw new Error(s||`Failed to broadcast transaction: ${e.statusText}`)}return await e.text()}catch(e){throw e instanceof Error?new Error(`Failed to broadcast BTC transaction: ${e.message}`):new Error("Failed to broadcast BTC transaction: Unknown error")}}async function D(n,t){return H(`${t}/tx/${n}`)}async function Q(n,t){try{const e=await fetch(`${t}/tx/${n}/hex`);if(!e.ok){const r=await e.text();throw new Error(`Mempool API error (${e.status}): ${r||e.statusText}`)}return await e.text()}catch(e){throw e instanceof Error?new Error(`Failed to get transaction hex for ${n}: ${e.message}`):new Error(`Failed to get transaction hex for ${n}: Unknown error`)}}async function X(n,t,e){const r=await D(n,e);if(t>=r.vout.length)throw new Error(`Invalid vout ${t} for transaction ${n} (has ${r.vout.length} outputs)`);const a=r.vout[t];return{txid:n,vout:t,value:a.value,scriptPubKey:a.scriptpubkey}}async function tt(n,t){try{const e=await H(`${t}/address/${n}/utxo`),r=await H(`${t}/v1/validate-address/${n}`);if(!r.isvalid)throw new Error(`Invalid Bitcoin address: ${n}. Mempool API validation failed.`);return e.sort((s,c)=>c.value-s.value).map(s=>({txid:s.txid,vout:s.vout,value:s.value,scriptPubKey:r.scriptPubKey,confirmed:s.status.confirmed}))}catch(e){throw e instanceof Error?new Error(`Failed to get UTXOs for address ${n}: ${e.message}`):new Error(`Failed to get UTXOs for address ${n}: Unknown error`)}}function et(n){return _[n]}async function nt(n,t){return H(`${t}/address/${n}/txs`)}async function rt(n){const t=await fetch(`${n}/v1/fees/recommended`);if(!t.ok)throw new Error(`Failed to fetch network fees: ${t.status} ${t.statusText}`);const e=await t.json();if(typeof e.fastestFee!="number"||typeof e.halfHourFee!="number"||typeof e.hourFee!="number"||typeof e.economyFee!="number"||typeof e.minimumFee!="number")throw new Error("Invalid fee data structure from mempool API. Expected all fee fields to be numbers.");return e}const I=[{type:"function",name:"submitPeginRequest",inputs:[{name:"depositor",type:"address",internalType:"address"},{name:"depositorBtcPubKey",type:"bytes32",internalType:"bytes32"},{name:"btcPopSignature",type:"bytes",internalType:"bytes"},{name:"unsignedPrePeginTx",type:"bytes",internalType:"bytes"},{name:"depositorSignedPeginTx",type:"bytes",internalType:"bytes"},{name:"vaultProvider",type:"address",internalType:"address"},{name:"hashlock",type:"bytes32",internalType:"bytes32"},{name:"htlcVout",type:"uint8",internalType:"uint8"},{name:"depositorPayoutBtcAddress",type:"bytes",internalType:"bytes"},{name:"depositorLamportPkHash",type:"bytes32",internalType:"bytes32"}],outputs:[{name:"",type:"bytes32",internalType:"bytes32"}],stateMutability:"payable"},{type:"function",name:"submitPeginRequest",inputs:[{name:"depositor",type:"address",internalType:"address"},{name:"depositorBtcPubKey",type:"bytes32",internalType:"bytes32"},{name:"btcPopSignature",type:"bytes",internalType:"bytes"},{name:"unsignedPrePeginTx",type:"bytes",internalType:"bytes"},{name:"depositorSignedPeginTx",type:"bytes",internalType:"bytes"},{name:"vaultProvider",type:"address",internalType:"address"},{name:"hashlock",type:"bytes32",internalType:"bytes32"},{name:"htlcVout",type:"uint8",internalType:"uint8"},{name:"referralCode",type:"uint32",internalType:"uint32"},{name:"depositorPayoutBtcAddress",type:"bytes",internalType:"bytes"},{name:"depositorLamportPkHash",type:"bytes32",internalType:"bytes32"}],outputs:[{name:"",type:"bytes32",internalType:"bytes32"}],stateMutability:"payable"},{type:"function",name:"activateVaultWithSecret",inputs:[{name:"vaultId",type:"bytes32",internalType:"bytes32"},{name:"s",type:"bytes32",internalType:"bytes32"}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"getPegInFee",inputs:[{name:"vaultProvider",type:"address",internalType:"address"}],outputs:[{name:"totalFee",type:"uint256",internalType:"uint256"}],stateMutability:"view"},{type:"function",name:"getBTCVault",inputs:[{name:"vaultId",type:"bytes32",internalType:"bytes32"}],outputs:[{name:"vault",type:"tuple",internalType:"struct IBTCVaultRegistry.BTCVault",components:[{name:"depositor",type:"address",internalType:"address"},{name:"depositorBtcPubKey",type:"bytes32",internalType:"bytes32"},{name:"depositorSignedPeginTx",type:"bytes",internalType:"bytes"},{name:"amount",type:"uint256",internalType:"uint256"},{name:"vaultProvider",type:"address",internalType:"address"},{name:"status",type:"uint8",internalType:"enum IBTCVaultRegistry.BTCVaultStatus"},{name:"applicationEntryPoint",type:"address",internalType:"address"},{name:"universalChallengersVersion",type:"uint16",internalType:"uint16"},{name:"appVaultKeepersVersion",type:"uint16",internalType:"uint16"},{name:"offchainParamsVersion",type:"uint16",internalType:"uint16"},{name:"proverProgramVersion",type:"uint16",internalType:"uint16"},{name:"createdAt",type:"uint256",internalType:"uint256"},{name:"verifiedAt",type:"uint256",internalType:"uint256"},{name:"depositorLamportPkHash",type:"bytes32",internalType:"bytes32"},{name:"hashlock",type:"bytes32",internalType:"bytes32"},{name:"htlcVout",type:"uint8",internalType:"uint8"}]}],stateMutability:"view"},{type:"error",name:"InvalidPeginFee",inputs:[{name:"provided",type:"uint256",internalType:"uint256"},{name:"required",type:"uint256",internalType:"uint256"}]},{type:"error",name:"InvalidSecret",inputs:[]},{type:"error",name:"ActivationDeadlineExpired",inputs:[]},{type:"error",name:"InvalidHashlock",inputs:[]},{type:"error",name:"DuplicateHashlock",inputs:[]},{type:"error",name:"CapExceeded",inputs:[]},{type:"error",name:"InvalidOutputIndex",inputs:[]},{type:"error",name:"PeginSignaturesIncomplete",inputs:[]}],m={"0x04aabf33":"Vault already exists: This Bitcoin transaction has already been registered. Please select different UTXOs or use a different amount to create a unique transaction.","0x4fec082d":"Script mismatch: The Bitcoin transaction's taproot output does not match the expected vault script. This may be caused by incorrect vault participants or key configuration.","0x6cc363a5":"Invalid BTC proof of possession: The signature could not be verified. Please ensure you're signing with the correct Bitcoin wallet.","0x6c3f2bf6":"Invalid BTC public key: The Bitcoin public key format is invalid.","0x2c5211c6":"Invalid amount: The deposit amount is invalid or below the minimum required.","0x0405f772":"Application not registered: The application controller is not registered in the system.","0x24e165cc":"Invalid provider status: The vault provider is not in a valid state to accept deposits.","0xd92e233d":"Zero address: One of the required addresses is the zero address.","0x65aa7007":"BTC key mismatch: The Bitcoin public key does not match the expected key.","0x82b42900":"Unauthorized: You must be the depositor or vault provider to submit this transaction.","0x8baa579f":"Invalid signature: The BTC proof of possession signature could not be verified.","0x2f9d01e9":"Invalid BTC transaction: The Bitcoin transaction format is invalid.","0x5a3c6b3e":"Vault provider not registered: The selected vault provider is not registered.","0x979f4518":"Invalid pegin fee: The ETH fee sent does not match the required amount. This may indicate a fee rate change during the transaction."};function $(n){if(!n||typeof n!="object")return;const t=n;if(typeof t.data=="string"&&t.data.startsWith("0x"))return t.data;if(typeof t.details=="string"&&t.details.startsWith("0x"))return t.details;let e=t.cause,r=0;const a=5;for(;e&&typeof e=="object"&&r<a;){const i=e;if(typeof i.data=="string"&&i.data.startsWith("0x"))return i.data;e=i.cause,r++}const c=(typeof t.message=="string"?t.message:"").match(/\b(0x[a-fA-F0-9]{8})\b/);if(c)return c[1]}function st(n){const t=$(n);if(t){const e=t.substring(0,10);return m[t]??m[e]}}function ot(n){const t=$(n);if(t===void 0)return!1;const e=t.substring(0,10);return t in m||e in m}function A(n){console.error("[Contract Error] Raw error:",n);const t=$(n);if(console.error("[Contract Error] Extracted error data:",t),t){const r=t.substring(0,10),a=m[t]??m[r];if(a)throw console.error("[Contract Error] Known error:",a),new Error(a)}const e=(n==null?void 0:n.message)||"";if(e.includes("gas limit too high")||e.includes("21000000")||e.includes("Internal JSON-RPC error")){const r=t?` (error code: ${t})`:"";throw console.error("[Contract Error] Transaction rejected. Error code:",t,"Message:",e),new Error(`Transaction failed: The contract rejected this transaction${r}. Possible causes: (1) Vault already exists for this transaction, (2) Invalid signature, (3) Unauthorized caller. Please check your transaction parameters and try again.`)}throw n instanceof Error?(console.error("[Contract Error] Unhandled error:",n.message),n):new Error(`Contract call failed: ${String(n)}`)}class at{constructor(t){C(this,"config");this.config=t}async preparePegin(t){const e=await this.config.btcWallet.getPublicKeyHex(),r=e.length===66?e.slice(2):e,a=u.stripHexPrefix(t.vaultProviderBtcPubkey),s=t.vaultKeeperBtcPubkeys.map(u.stripHexPrefix),c=t.universalChallengerBtcPubkeys.map(u.stripHexPrefix);if(t.hashlocks.length!==1)throw new Error("hashlocks must contain exactly one entry (batched deposits not yet supported)");const i=s.length,o={depositorPubkey:r,vaultProviderPubkey:a,vaultKeeperPubkeys:s,universalChallengerPubkeys:c,hashlocks:t.hashlocks,timelockRefund:t.timelockRefund,pegInAmount:t.amount,feeRate:t.protocolFeeRate,numLocalChallengers:i,councilQuorum:t.councilQuorum,councilSize:t.councilSize,network:this.config.btcNetwork},l=await u.buildPrePeginPsbt(o),d=W([...t.availableUTXOs],l.totalOutputValue,t.mempoolFeeRate),h=u.getNetwork(this.config.btcNetwork),g=u.fundPeginTransaction({unfundedTxHex:l.psbtHex,selectedUTXOs:d.selectedUTXOs,changeAddress:t.changeAddress,changeAmount:d.changeAmount,network:h}),b=u.stripHexPrefix(U(g)),T=await u.buildPeginTxFromFundedPrePegin({prePeginParams:o,timelockPegin:t.timelockPegin,fundedPrePeginTxHex:g,htlcVout:V.SINGLE_DEPOSIT_HTLC_VOUT}),v=await u.buildPeginInputPsbt({peginTxHex:T.txHex,fundedPrePeginTxHex:g,depositorPubkey:r,vaultProviderPubkey:a,vaultKeeperPubkeys:s,universalChallengerPubkeys:c,hashlock:t.hashlocks[0],timelockRefund:t.timelockRefund,network:this.config.btcNetwork}),p=await this.config.btcWallet.signPsbt(v.psbtHex,O.createTaprootScriptPathSignOptions(e,1)),f=u.extractPeginInputSignature(p,r),x=u.finalizePeginInputPsbt(p);return{fundedPrePeginTxHex:g,htlcValue:l.htlcValue,signedPeginInputPsbtHex:p,peginInputSignature:f,vaultScriptPubKey:T.vaultScriptPubKey,peginTxHex:x,prePeginTxid:b,peginTxid:T.txid,selectedUTXOs:d.selectedUTXOs,fee:d.fee,changeAmount:d.changeAmount}}async signAndBroadcast(t){const{fundedPrePeginTxHex:e,depositorBtcPubkey:r}=t,a=e.startsWith("0x")?e.slice(2):e,s=P.Transaction.fromHex(a);if(s.ins.length===0)throw new Error("Transaction has no inputs");const c=new P.Psbt;c.setVersion(s.version),c.setLocktime(s.locktime);const i=r.startsWith("0x")?r.slice(2):r;if(i.length!==64||!/^[0-9a-fA-F]+$/.test(i))throw new Error("Invalid depositorBtcPubkey: expected 64 hex characters (x-only pubkey)");const o=y.Buffer.from(i,"hex");if(o.length!==32)throw new Error(`Invalid depositorBtcPubkey length: expected 32 bytes, got ${o.length}`);const l=this.config.mempoolApiUrl,d=s.ins.map(p=>{const f=y.Buffer.from(p.hash).reverse().toString("hex"),x=p.index;return X(f,x,l).then(k=>({input:p,utxoData:k,txid:f,vout:x}))}),h=await Promise.all(d);for(const{input:p,utxoData:f,txid:x,vout:k}of h){const S=M({value:f.value,scriptPubKey:f.scriptPubKey},o);c.addInput({hash:p.hash,index:p.index,sequence:p.sequence,...S})}for(const p of s.outs)c.addOutput({script:p.script,value:p.value});const g=await this.config.btcWallet.signPsbt(c.toHex()),b=P.Psbt.fromHex(g);try{b.finalizeAllInputs()}catch(p){if(!b.data.inputs.every(x=>x.finalScriptWitness||x.finalScriptSig))throw new Error(`PSBT finalization failed and wallet did not auto-finalize: ${p}`)}const T=b.extractTransaction().toHex();return await K(T,l)}async registerPeginOnChain(t){const{depositorBtcPubkey:e,unsignedPrePeginTx:r,depositorSignedPeginTx:a,vaultProvider:s,hashlock:c,onPopSigned:i,depositorPayoutBtcAddress:o,depositorLamportPkHash:l,preSignedBtcPopSignature:d}=t;if(!this.config.ethWallet.account)throw new Error("Ethereum wallet account not found");const h=this.config.ethWallet.account.address,g=await this.resolvePopSignature(h,d);i&&await i();const b=u.ensureHexPrefix(e),T=u.ensureHexPrefix(r),v=u.ensureHexPrefix(a),p=await this.resolvePayoutScriptPubKey(o),f=U(v);if(await this.checkVaultExists(f))throw new Error(`Vault already exists for this transaction (ID: ${f}). Vault IDs are deterministically derived from the unsigned Bitcoin transaction, so using the same UTXOs and amount will always produce the same vault. To create a new vault, please use different UTXOs or a different amount to generate a unique transaction.`);const k=w.createPublicClient({chain:this.config.ethChain,transport:w.http()});let S;try{S=await k.readContract({address:this.config.vaultContracts.btcVaultRegistry,abi:I,functionName:"getPegInFee",args:[s]})}catch{throw new Error("Failed to query pegin fee from the contract. Please check your network connection and that the contract address is correct.")}const R=w.encodeFunctionData({abi:I,functionName:"submitPeginRequest",args:[h,b,g,T,v,s,c,V.SINGLE_DEPOSIT_HTLC_VOUT,p,l]});let F;try{F=await k.estimateGas({to:this.config.vaultContracts.btcVaultRegistry,data:R,value:S,account:this.config.ethWallet.account.address})}catch(B){A(B)}try{return{ethTxHash:await this.config.ethWallet.sendTransaction({to:this.config.vaultContracts.btcVaultRegistry,data:R,value:S,account:this.config.ethWallet.account,chain:this.config.ethChain,gas:F}),vaultId:f,btcPopSignature:g}}catch(B){A(B)}}async checkVaultExists(t){try{return(await w.createPublicClient({chain:this.config.ethChain,transport:w.http()}).readContract({address:this.config.vaultContracts.btcVaultRegistry,abi:I,functionName:"getBTCVault",args:[t]})).depositor!==w.zeroAddress}catch{return!1}}async resolvePayoutScriptPubKey(t){let e;if(t)e=t;else{e=await this.config.btcWallet.getAddress();const a=await this.config.btcWallet.getPublicKeyHex();if(!u.isAddressFromPublicKey(e,a,this.config.btcNetwork))throw new Error("The BTC address from your wallet does not match the wallet's public key. Please ensure your wallet is using a supported address type (Taproot or Native SegWit).")}const r=u.getNetwork(this.config.btcNetwork);try{return`0x${j.address.toOutputScript(e,r).toString("hex")}`}catch{throw new Error(`Invalid BTC payout address: "${e}". Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`)}}async resolvePopSignature(t,e){if(e)return e;const r=this.config.vaultContracts.btcVaultRegistry,a=`${t.toLowerCase()}:${this.config.ethChain.id}:pegin:${r.toLowerCase()}`,s=await this.config.btcWallet.signMessage(a,"bip322-simple");return s.startsWith("0x")?s:`0x${y.Buffer.from(s,"base64").toString("hex")}`}getNetwork(){return this.config.btcNetwork}getVaultContractAddress(){return this.config.vaultContracts.btcVaultRegistry}}class it{constructor(t){C(this,"config");this.config=t}async signPayoutTransaction(t){const e=await this.config.btcWallet.getPublicKeyHex(),{depositorPubkey:r}=u.validateWalletPubkey(e,t.depositorBtcPubkey),a=await u.buildPayoutPsbt({payoutTxHex:t.payoutTxHex,peginTxHex:t.peginTxHex,assertTxHex:t.assertTxHex,depositorBtcPubkey:r,vaultProviderBtcPubkey:t.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:t.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:t.universalChallengerBtcPubkeys,timelockPegin:t.timelockPegin,network:this.config.network}),s=await this.config.btcWallet.signPsbt(a.psbtHex,O.createTaprootScriptPathSignOptions(e,1));return{signature:u.extractPayoutSignature(s,r),depositorBtcPubkey:r}}getNetwork(){return this.config.network}supportsBatchSigning(){return typeof this.config.btcWallet.signPsbts=="function"}async signPayoutTransactionsBatch(t){if(!this.supportsBatchSigning())throw new Error("Wallet does not support batch signing (signPsbts method not available)");const e=await this.config.btcWallet.getPublicKeyHex(),r=[],a=[],s=[];for(const o of t){const{depositorPubkey:l}=u.validateWalletPubkey(e,o.depositorBtcPubkey);s.push(l);const d=await u.buildPayoutPsbt({payoutTxHex:o.payoutTxHex,peginTxHex:o.peginTxHex,assertTxHex:o.assertTxHex,depositorBtcPubkey:l,vaultProviderBtcPubkey:o.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:o.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:o.universalChallengerBtcPubkeys,timelockPegin:o.timelockPegin,network:this.config.network});r.push(d.psbtHex),a.push(O.createTaprootScriptPathSignOptions(e,1))}const c=await this.config.btcWallet.signPsbts(r,a);if(c.length!==t.length)throw new Error(`Expected ${t.length} signed PSBTs but received ${c.length}`);const i=[];for(let o=0;o<t.length;o++){const l=s[o],d=u.extractPayoutSignature(c[o],l);i.push({payoutSignature:d,depositorBtcPubkey:l})}return i}}exports.BTCVaultRegistryABI=I;exports.BitcoinScriptType=E;exports.CONTRACT_ERRORS=m;exports.MEMPOOL_API_URLS=_;exports.PayoutManager=it;exports.PeginManager=at;exports.calculateBtcTxHash=U;exports.createSplitTransaction=J;exports.createSplitTransactionPsbt=Y;exports.extractErrorData=$;exports.getAddressTxs=nt;exports.getAddressUtxos=tt;exports.getContractErrorMessage=st;exports.getDustThreshold=Z;exports.getMempoolApiUrl=et;exports.getNetworkFees=rt;exports.getPsbtInputFields=M;exports.getScriptType=N;exports.getTxHex=Q;exports.getTxInfo=D;exports.getUtxoInfo=X;exports.handleContractError=A;exports.isKnownContractError=ot;exports.pushTx=K;exports.selectUtxosForPegin=W;exports.shouldAddChangeOutput=G;
|
|
2
|
+
//# sourceMappingURL=PayoutManager-9qwA76_B.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PayoutManager-9qwA76_B.cjs","sources":["../src/tbv/core/utils/utxo/selectUtxos.ts","../src/tbv/core/utils/transaction/btcTxHash.ts","../src/tbv/core/utils/transaction/createSplitTransaction.ts","../src/tbv/core/utils/btc/scriptType.ts","../src/tbv/core/utils/btc/psbtInputFields.ts","../src/tbv/core/clients/mempool/mempoolApi.ts","../src/tbv/core/contracts/abis/BTCVaultRegistry.abi.ts","../src/tbv/core/contracts/errors.ts","../src/tbv/core/managers/PeginManager.ts","../src/tbv/core/managers/PayoutManager.ts"],"sourcesContent":["/**\n * UTXO selection utilities for peg-in transactions.\n * Follows btc-staking-ts methodology with iterative fee calculation.\n */\n\nimport { script as bitcoinScript } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport {\n BTC_DUST_SAT,\n DUST_THRESHOLD,\n MAX_NON_LEGACY_OUTPUT_SIZE,\n P2TR_INPUT_SIZE,\n rateBasedTxBufferFee,\n TX_BUFFER_SIZE_OVERHEAD,\n} from \"../fee/constants\";\n\n/**\n * Unspent Transaction Output (UTXO) for funding peg-in transactions.\n */\nexport interface UTXO {\n /**\n * Transaction ID of the UTXO (64-char hex without 0x prefix).\n */\n txid: string;\n\n /**\n * Output index within the transaction.\n */\n vout: number;\n\n /**\n * Value in satoshis.\n */\n value: number;\n\n /**\n * Script public key hex.\n */\n scriptPubKey: string;\n}\n\nexport interface UTXOSelectionResult {\n selectedUTXOs: UTXO[];\n totalValue: bigint;\n fee: bigint;\n changeAmount: bigint;\n}\n\n/**\n * Selects UTXOs to fund a peg-in transaction with iterative fee calculation.\n *\n * This function implements the btc-staking-ts approach:\n * 1. Filter UTXOs for script validity (no minimum value filter)\n * 2. Sort by value (largest first) to minimize number of inputs\n * 3. Iteratively add UTXOs and recalculate fee until we have enough\n *\n * The fee recalculation is critical because:\n * - Each UTXO added increases transaction size → increases fee\n * - More fee needed might require another UTXO\n * - Change output detection affects fee (adds output size if needed)\n *\n * @param availableUTXOs - All available UTXOs from wallet\n * @param peginAmount - Amount to peg in (satoshis)\n * @param feeRate - Fee rate (sat/vbyte)\n * @returns Selected UTXOs, total value, calculated fee, and change amount\n * @throws Error if insufficient funds or no valid UTXOs\n */\nexport function selectUtxosForPegin(\n availableUTXOs: UTXO[],\n peginAmount: bigint,\n feeRate: number,\n): UTXOSelectionResult {\n if (availableUTXOs.length === 0) {\n throw new Error(\"Insufficient funds: no UTXOs available\");\n }\n\n // Filter for script validity ONLY (matching btc-staking-ts approach)\n // No minimum value filter - we accept any UTXO with valid script\n const validUTXOs = availableUTXOs.filter((utxo) => {\n const script = Buffer.from(utxo.scriptPubKey, \"hex\");\n const decompiledScript = bitcoinScript.decompile(script);\n return !!decompiledScript;\n });\n\n if (validUTXOs.length === 0) {\n throw new Error(\n \"Insufficient funds: no valid UTXOs available (all have invalid scripts)\",\n );\n }\n\n // Sort by value: HIGHEST to LOWEST (use big UTXOs first)\n // Use spread to avoid mutating the original array\n const sortedUTXOs = [...validUTXOs].sort((a, b) => b.value - a.value);\n\n const selectedUTXOs: UTXO[] = [];\n let accumulatedValue = 0n;\n let estimatedFee = 0n;\n\n // Iteratively select UTXOs and recalculate fee\n for (const utxo of sortedUTXOs) {\n selectedUTXOs.push(utxo);\n accumulatedValue += BigInt(utxo.value);\n\n // Recalculate fee based on CURRENT number of inputs\n const inputSize = selectedUTXOs.length * P2TR_INPUT_SIZE;\n const outputSize = 2 * MAX_NON_LEGACY_OUTPUT_SIZE; // vault + depositor claim outputs\n const baseTxSize = inputSize + outputSize + TX_BUFFER_SIZE_OVERHEAD;\n\n // Calculate base fee with buffer\n estimatedFee =\n BigInt(Math.ceil(baseTxSize * feeRate)) +\n BigInt(rateBasedTxBufferFee(feeRate));\n\n // Check if there will be change left after pegin amount and fee\n const changeAmount = accumulatedValue - peginAmount - estimatedFee;\n\n // If change is above dust, add fee for change output\n if (changeAmount > DUST_THRESHOLD) {\n const changeOutputFee = BigInt(\n Math.ceil(MAX_NON_LEGACY_OUTPUT_SIZE * feeRate),\n );\n estimatedFee += changeOutputFee;\n }\n\n // Check if we have enough to cover pegin amount + fees\n if (accumulatedValue >= peginAmount + estimatedFee) {\n // Success! We have enough funds\n const finalChangeAmount = accumulatedValue - peginAmount - estimatedFee;\n\n return {\n selectedUTXOs,\n totalValue: accumulatedValue,\n fee: estimatedFee,\n changeAmount: finalChangeAmount,\n };\n }\n }\n\n // If we get here, we don't have enough funds\n throw new Error(\n `Insufficient funds: need ${peginAmount + estimatedFee} sats (${peginAmount} pegin + ${estimatedFee} fee), have ${accumulatedValue} sats`,\n );\n}\n\n/**\n * Checks if change amount is above dust threshold.\n *\n * @param changeAmount - Change amount in satoshis\n * @returns true if change should be added as output, false if it should go to miners\n */\nexport function shouldAddChangeOutput(changeAmount: bigint): boolean {\n return changeAmount > DUST_THRESHOLD;\n}\n\n/**\n * Gets the dust threshold value.\n *\n * @returns Dust threshold in satoshis\n */\nexport function getDustThreshold(): number {\n return BTC_DUST_SAT;\n}\n","/**\n * Bitcoin Transaction Hash Utilities\n *\n * Provides utilities for calculating Bitcoin transaction hashes in a way that matches\n * the contract's BtcUtils.hashBtcTx() implementation.\n */\n\nimport { Transaction } from \"bitcoinjs-lib\";\nimport type { Hex } from \"viem\";\n\n/**\n * Calculate Bitcoin transaction hash\n *\n * This matches the contract's BtcUtils.hashBtcTx() implementation:\n * 1. Double SHA256 the transaction bytes\n * 2. Reverse the byte order (Bitcoin convention)\n *\n * The resulting hash is used as the unique vault identifier in the BTCVaultRegistry contract.\n *\n * @param txHex - Transaction hex (with or without 0x prefix)\n * @returns The transaction hash as Hex (with 0x prefix)\n */\nexport function calculateBtcTxHash(txHex: string): Hex {\n // Remove 0x prefix if present\n const cleanHex = txHex.startsWith(\"0x\") ? txHex.slice(2) : txHex;\n\n // Use bitcoinjs-lib to calculate transaction ID (already does double SHA256 + reverse)\n const tx = Transaction.fromHex(cleanHex);\n const txid = tx.getId();\n\n // Return with 0x prefix to match Ethereum hex format\n return `0x${txid}` as Hex;\n}\n","/**\n * UTXO Split Transaction Builder\n *\n * Creates Bitcoin transactions that split input UTXOs into multiple outputs.\n * Used for multi-vault peg-in flow when user doesn't have enough separate UTXOs.\n *\n * Transaction Flow:\n * 1. createSplitTransaction() → unsigned transaction with deterministic txid\n * 2. createSplitTransactionPsbt() → PSBT ready for wallet signing\n * 3. Wallet signs PSBT → signed transaction\n * 4. Broadcast to Bitcoin network → outputs become available for pegin transactions\n *\n * @module utils/transaction/createSplitTransaction\n */\n\nimport { address as bitcoinAddress, Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport type { Network } from \"../../primitives\";\nimport type { UTXO } from \"../utxo/selectUtxos\";\n\nimport { getNetwork } from \"./fundPeginTransaction\";\n\n/**\n * Output specification for split transaction.\n */\nexport interface SplitOutput {\n /** Amount in satoshis */\n amount: bigint;\n /** Bitcoin address to send to */\n address: string;\n}\n\n/**\n * Result of creating a split transaction.\n */\nexport interface SplitTransactionResult {\n /** Unsigned transaction hex */\n txHex: string;\n /** Transaction ID (deterministic, calculated before signing) */\n txid: string;\n /** Output UTXOs that will be created when transaction is broadcast */\n outputs: Array<{\n /** Transaction ID of this output */\n txid: string;\n /** Output index */\n vout: number;\n /** Amount in satoshis */\n value: number;\n /** Script pubkey hex */\n scriptPubKey: string;\n }>;\n}\n\n/**\n * Create a UTXO split transaction.\n *\n * This function creates a Bitcoin transaction that takes input UTXOs\n * and splits them into multiple outputs with specified amounts.\n *\n * The transaction is returned unsigned. The caller must:\n * 1. Sign the transaction using a Bitcoin wallet\n * 2. Broadcast it to the Bitcoin network\n * 3. Use the output UTXOs for subsequent peg-in transactions\n *\n * @param inputs - Input UTXOs to split\n * @param outputs - Desired output amounts and addresses\n * @param network - Bitcoin network (mainnet, testnet, signet, regtest)\n * @returns Unsigned transaction hex, txid, and output UTXO references\n * @throws Error if inputs or outputs are empty\n * @throws Error if address decoding fails (invalid address for network)\n *\n * @example\n * ```typescript\n * const result = createSplitTransaction(\n * [{ txid: \"abc...\", vout: 0, value: 100000, scriptPubKey: \"...\" }],\n * [\n * { amount: 50000n, address: \"tb1p...\" },\n * { amount: 45000n, address: \"tb1p...\" }\n * ],\n * \"testnet\"\n * );\n * // result.txHex → unsigned transaction\n * // result.txid → deterministic transaction ID\n * // result.outputs → UTXO references for pegin creation\n * ```\n */\nexport function createSplitTransaction(\n inputs: UTXO[],\n outputs: SplitOutput[],\n network: Network,\n): SplitTransactionResult {\n // Validate inputs\n if (inputs.length === 0) {\n throw new Error(\"No input UTXOs provided for split transaction\");\n }\n\n if (outputs.length === 0) {\n throw new Error(\"No outputs specified for split transaction\");\n }\n\n // Validate all output amounts are positive\n for (const output of outputs) {\n if (output.amount <= 0n) {\n throw new Error(\n `Invalid output amount for ${output.address}: ${output.amount} satoshis. ` +\n `Amount must be greater than zero.`,\n );\n }\n }\n\n // Get bitcoinjs-lib network\n const btcNetwork = getNetwork(network);\n\n // Create transaction with BIP 68/112/113 compatibility\n const tx = new Transaction();\n tx.version = 2;\n\n // Add inputs\n for (const input of inputs) {\n // Bitcoin uses reversed byte order for txid\n const txidBuffer = Buffer.from(input.txid, \"hex\").reverse();\n tx.addInput(txidBuffer, input.vout);\n }\n\n // Add outputs\n const outputUtxos: SplitTransactionResult[\"outputs\"] = [];\n\n for (let i = 0; i < outputs.length; i++) {\n const output = outputs[i];\n\n // Decode address to get script pubkey\n let outputScript: Buffer;\n try {\n const decoded = bitcoinAddress.toOutputScript(output.address, btcNetwork);\n outputScript = decoded;\n } catch (error) {\n throw new Error(\n `Failed to decode address \"${output.address}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n tx.addOutput(outputScript, Number(output.amount));\n\n // Store output UTXO reference (will be created when tx is broadcast)\n outputUtxos.push({\n txid: \"\", // Will be set after txid calculation\n vout: i,\n value: Number(output.amount),\n scriptPubKey: outputScript.toString(\"hex\"),\n });\n }\n\n // Get unsigned transaction hex\n const txHex = tx.toHex();\n\n // Calculate txid (this is deterministic for unsigned transactions)\n const txid = tx.getId();\n\n // Update output UTXO txids\n for (const output of outputUtxos) {\n output.txid = txid;\n }\n\n return {\n txHex,\n txid,\n outputs: outputUtxos,\n };\n}\n\n/**\n * Create a PSBT for signing a split transaction with Taproot inputs.\n *\n * IMPORTANT: This function assumes ALL inputs are P2TR (Taproot) addresses.\n * It unconditionally adds tapInternalKey for Taproot signing. Using non-P2TR\n * inputs will cause wallet signing failures.\n *\n * This function takes an unsigned split transaction and creates a PSBT\n * that is intended to be signed by a Bitcoin wallet; this function does not\n * perform any signing itself.\n *\n * The PSBT includes:\n * - witnessUtxo: Script and value for each input (required for segwit)\n * - tapInternalKey: Depositor's x-only pubkey (required for P2TR signing)\n *\n * Technical Note:\n * For P2TR (Taproot) inputs, we need the witnessUtxo and tapInternalKey.\n * This is different from legacy inputs which would need the full previous transaction.\n *\n * @param unsignedTxHex - Unsigned transaction hex from createSplitTransaction\n * @param inputs - Input UTXOs with full data for PSBT\n * @param publicKeyNoCoord - Depositor's public key (x-only, 32 bytes) for P2TR signing\n * @returns PSBT hex ready for wallet signing\n * @throws Error if publicKeyNoCoord is not a 32-byte Buffer\n * @throws Error if UTXO count doesn't match transaction inputs\n * @throws Error if any input is not P2TR format\n *\n * @example\n * ```typescript\n * const psbtHex = createSplitTransactionPsbt(\n * result.txHex,\n * inputUtxos,\n * Buffer.from(depositorPubkeyXOnly, \"hex\")\n * );\n * // Sign via wallet\n * const signedPsbtHex = await wallet.signPsbt(psbtHex);\n * ```\n */\nexport function createSplitTransactionPsbt(\n unsignedTxHex: string,\n inputs: UTXO[],\n publicKeyNoCoord: Buffer,\n): string {\n const tx = Transaction.fromHex(unsignedTxHex);\n const psbt = new Psbt();\n\n psbt.setVersion(tx.version);\n psbt.setLocktime(tx.locktime);\n\n // Validate tapInternalKey is a 32-byte x-only public key\n if (!Buffer.isBuffer(publicKeyNoCoord) || publicKeyNoCoord.length !== 32) {\n throw new Error(\n `Invalid publicKeyNoCoord: expected 32-byte Buffer (x-only pubkey), got ${\n Buffer.isBuffer(publicKeyNoCoord)\n ? `${publicKeyNoCoord.length}-byte Buffer`\n : typeof publicKeyNoCoord\n }`,\n );\n }\n\n // Validate UTXO array length matches transaction inputs\n if (inputs.length !== tx.ins.length) {\n throw new Error(\n `UTXO count mismatch: transaction has ${tx.ins.length} input${tx.ins.length !== 1 ? \"s\" : \"\"}, ` +\n `but ${inputs.length} UTXO${inputs.length !== 1 ? \"s were\" : \" was\"} provided`,\n );\n }\n\n // Add inputs with UTXO data for P2TR signing\n for (let i = 0; i < tx.ins.length; i++) {\n const input = tx.ins[i];\n const utxo = inputs[i];\n\n if (!utxo) {\n throw new Error(`Missing UTXO data for input ${i}`);\n }\n\n // Validate UTXO outpoint matches transaction input\n const expectedTxid = Buffer.from(input.hash).reverse().toString(\"hex\");\n const expectedVout = input.index;\n\n if (utxo.txid !== expectedTxid || utxo.vout !== expectedVout) {\n throw new Error(\n `Input ${i} outpoint mismatch: ` +\n `transaction expects ${expectedTxid}:${expectedVout}, ` +\n `but UTXO ${utxo.txid}:${utxo.vout} was provided. ` +\n `Ensure inputs array matches the order used in createSplitTransaction().`,\n );\n }\n\n // Validate input is P2TR (required for tapInternalKey)\n const inputScript = Buffer.from(utxo.scriptPubKey, \"hex\");\n const isP2TR =\n inputScript.length === 34 &&\n inputScript[0] === 0x51 && // OP_1 (witness version 1)\n inputScript[1] === 0x20; // push 32 bytes\n\n if (!isP2TR) {\n throw new Error(\n `Input ${i} must be P2TR (Taproot). ` +\n `createSplitTransactionPsbt() requires P2TR inputs because it uses ` +\n `tapInternalKey for Taproot signing. ` +\n `ScriptPubKey: ${utxo.scriptPubKey.substring(0, 20)}...`,\n );\n }\n\n // IMPORTANT: Assumes P2TR inputs. tapInternalKey is only valid for Taproot.\n // Using this function with non-P2TR inputs will cause wallet signing to fail.\n const witnessUtxo = {\n script: Buffer.from(utxo.scriptPubKey, \"hex\"),\n value: utxo.value,\n };\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo,\n tapInternalKey: publicKeyNoCoord,\n });\n }\n\n // Add outputs\n for (const output of tx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n","/**\n * Bitcoin Script Type Detection\n *\n * Utilities to detect Bitcoin script types for proper PSBT input construction.\n *\n * @module utils/btc/scriptType\n */\n\n/**\n * Bitcoin script types.\n */\nexport enum BitcoinScriptType {\n P2PKH = \"P2PKH\",\n P2SH = \"P2SH\",\n P2WPKH = \"P2WPKH\",\n P2WSH = \"P2WSH\",\n P2TR = \"P2TR\",\n UNKNOWN = \"UNKNOWN\",\n}\n\n/**\n * Detect the type of a Bitcoin script.\n *\n * @param scriptPubKey - The script public key buffer\n * @returns The detected script type\n *\n * @example\n * ```typescript\n * const scriptType = getScriptType(Buffer.from(scriptPubKeyHex, 'hex'));\n * if (scriptType === BitcoinScriptType.P2TR) {\n * // Handle Taproot input\n * }\n * ```\n */\nexport function getScriptType(scriptPubKey: Buffer): BitcoinScriptType {\n const length = scriptPubKey.length;\n\n // P2PKH: OP_DUP OP_HASH160 <20 bytes> OP_EQUALVERIFY OP_CHECKSIG (25 bytes)\n if (\n length === 25 &&\n scriptPubKey[0] === 0x76 && // OP_DUP\n scriptPubKey[1] === 0xa9 && // OP_HASH160\n scriptPubKey[2] === 0x14 && // Push 20 bytes\n scriptPubKey[23] === 0x88 && // OP_EQUALVERIFY\n scriptPubKey[24] === 0xac // OP_CHECKSIG\n ) {\n return BitcoinScriptType.P2PKH;\n }\n\n // P2SH: OP_HASH160 <20 bytes> OP_EQUAL (23 bytes)\n if (\n length === 23 &&\n scriptPubKey[0] === 0xa9 && // OP_HASH160\n scriptPubKey[1] === 0x14 && // Push 20 bytes\n scriptPubKey[22] === 0x87 // OP_EQUAL\n ) {\n return BitcoinScriptType.P2SH;\n }\n\n // P2WPKH: OP_0 <20 bytes> (22 bytes)\n if (\n length === 22 &&\n scriptPubKey[0] === 0x00 && // OP_0\n scriptPubKey[1] === 0x14 // Push 20 bytes\n ) {\n return BitcoinScriptType.P2WPKH;\n }\n\n // P2WSH: OP_0 <32 bytes> (34 bytes)\n if (\n length === 34 &&\n scriptPubKey[0] === 0x00 && // OP_0\n scriptPubKey[1] === 0x20 // Push 32 bytes\n ) {\n return BitcoinScriptType.P2WSH;\n }\n\n // P2TR (Taproot): OP_1 <32 bytes> (34 bytes)\n if (\n length === 34 &&\n scriptPubKey[0] === 0x51 && // OP_1\n scriptPubKey[1] === 0x20 // Push 32 bytes\n ) {\n return BitcoinScriptType.P2TR;\n }\n\n return BitcoinScriptType.UNKNOWN;\n}\n\n","/**\n * PSBT Input Field Construction\n *\n * Constructs the correct PSBT input fields for a given UTXO based on its script type.\n *\n * @module utils/btc/psbtInputFields\n */\n\nimport { Buffer } from \"buffer\";\n\nimport { BitcoinScriptType, getScriptType } from \"./scriptType\";\n\n/**\n * PSBT input fields for supported script types (P2TR, P2WPKH, P2WSH).\n */\nexport interface PsbtInputFields {\n witnessUtxo?: {\n script: Buffer;\n value: number;\n };\n witnessScript?: Buffer;\n tapInternalKey?: Buffer;\n}\n\n/**\n * UTXO information for PSBT construction.\n *\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n */\nexport interface UtxoForPsbt {\n /** Transaction ID of the UTXO */\n txid: string;\n /** Output index (vout) of the UTXO */\n vout: number;\n /** Value of the UTXO in satoshis */\n value: number;\n /** ScriptPubKey of the UTXO (hex string) */\n scriptPubKey: string;\n /** Witness script (required for P2WSH) */\n witnessScript?: string;\n}\n\n/**\n * Get PSBT input fields for a given UTXO based on its script type.\n *\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n *\n * @param utxo - The unspent transaction output to process\n * @param publicKeyNoCoord - The x-only public key (32 bytes) for Taproot signing\n * @returns PSBT input fields object containing the necessary data\n * @throws Error if required input data is missing or unsupported script type\n */\nexport function getPsbtInputFields(\n utxo: UtxoForPsbt,\n publicKeyNoCoord?: Buffer,\n): PsbtInputFields {\n const scriptPubKey = Buffer.from(utxo.scriptPubKey, \"hex\");\n const type = getScriptType(scriptPubKey);\n\n switch (type) {\n case BitcoinScriptType.P2WPKH: {\n return {\n witnessUtxo: {\n script: scriptPubKey,\n value: utxo.value,\n },\n };\n }\n\n case BitcoinScriptType.P2WSH: {\n if (!utxo.witnessScript) {\n throw new Error(\"Missing witnessScript for P2WSH input\");\n }\n return {\n witnessUtxo: {\n script: scriptPubKey,\n value: utxo.value,\n },\n witnessScript: Buffer.from(utxo.witnessScript, \"hex\"),\n };\n }\n\n case BitcoinScriptType.P2TR: {\n if (publicKeyNoCoord && publicKeyNoCoord.length !== 32) {\n throw new Error(\n `Invalid tapInternalKey length: expected 32 bytes, got ${publicKeyNoCoord.length}`,\n );\n }\n return {\n witnessUtxo: {\n script: scriptPubKey,\n value: utxo.value,\n },\n // tapInternalKey is needed for Taproot signing\n ...(publicKeyNoCoord && { tapInternalKey: publicKeyNoCoord }),\n };\n }\n\n default:\n throw new Error(`Unsupported script type: ${type}`);\n }\n}\n\n","/**\n * Mempool API Client\n *\n * Client for interacting with mempool.space API for Bitcoin network operations.\n * Used for broadcasting transactions and fetching UTXO data.\n *\n * @module clients/mempool/mempoolApi\n */\n\nimport type { MempoolUTXO, NetworkFees, TxInfo, UtxoInfo } from \"./types\";\n\n/**\n * Default mempool API URLs by network.\n */\nexport const MEMPOOL_API_URLS = {\n mainnet: \"https://mempool.space/api\",\n testnet: \"https://mempool.space/testnet/api\",\n signet: \"https://mempool.space/signet/api\",\n} as const;\n\n/**\n * Fetch wrapper with error handling.\n */\nasync function fetchApi<T>(\n url: string,\n options?: RequestInit,\n): Promise<T> {\n try {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Mempool API error (${response.status}): ${errorText || response.statusText}`,\n );\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n return (await response.json()) as T;\n } else {\n return (await response.text()) as T;\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to fetch from mempool API: ${error.message}`);\n }\n throw new Error(\"Failed to fetch from mempool API: Unknown error\");\n }\n}\n\n/**\n * Push a signed transaction to the Bitcoin network.\n *\n * @param txHex - The signed transaction hex string\n * @param apiUrl - Mempool API base URL\n * @returns The transaction ID\n * @throws Error if broadcasting fails\n */\nexport async function pushTx(txHex: string, apiUrl: string): Promise<string> {\n try {\n const response = await fetch(`${apiUrl}/tx`, {\n method: \"POST\",\n body: txHex,\n headers: {\n \"Content-Type\": \"text/plain\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n // Try to extract error message from response using robust JSON parsing\n let message: string | undefined;\n try {\n const errorJson = JSON.parse(errorText);\n message = errorJson.message;\n } catch {\n // Not JSON, use raw text\n message = errorText;\n }\n throw new Error(\n message || `Failed to broadcast transaction: ${response.statusText}`,\n );\n }\n\n // Response is the transaction ID (plain text)\n const txId = await response.text();\n return txId;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to broadcast BTC transaction: ${error.message}`);\n }\n throw new Error(\"Failed to broadcast BTC transaction: Unknown error\");\n }\n}\n\n/**\n * Get transaction information from mempool.\n *\n * @param txid - The transaction ID\n * @param apiUrl - Mempool API base URL\n * @returns Transaction information\n */\nexport async function getTxInfo(txid: string, apiUrl: string): Promise<TxInfo> {\n return fetchApi<TxInfo>(`${apiUrl}/tx/${txid}`);\n}\n\n/**\n * Get the hex representation of a transaction.\n *\n * @param txid - The transaction ID\n * @param apiUrl - Mempool API base URL\n * @returns The transaction hex string\n * @throws Error if the request fails or transaction is not found\n */\nexport async function getTxHex(txid: string, apiUrl: string): Promise<string> {\n try {\n const response = await fetch(`${apiUrl}/tx/${txid}/hex`);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Mempool API error (${response.status}): ${errorText || response.statusText}`,\n );\n }\n\n return await response.text();\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to get transaction hex for ${txid}: ${error.message}`);\n }\n throw new Error(`Failed to get transaction hex for ${txid}: Unknown error`);\n }\n}\n\n/**\n * Get UTXO information for a specific transaction output.\n *\n * This is used for constructing PSBTs where we need the witnessUtxo data.\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n *\n * @param txid - The transaction ID containing the UTXO\n * @param vout - The output index\n * @param apiUrl - Mempool API base URL\n * @returns UTXO information with value and scriptPubKey\n */\nexport async function getUtxoInfo(\n txid: string,\n vout: number,\n apiUrl: string,\n): Promise<UtxoInfo> {\n const txInfo = await getTxInfo(txid, apiUrl);\n\n if (vout >= txInfo.vout.length) {\n throw new Error(\n `Invalid vout ${vout} for transaction ${txid} (has ${txInfo.vout.length} outputs)`,\n );\n }\n\n const output = txInfo.vout[vout];\n\n return {\n txid,\n vout,\n value: output.value,\n scriptPubKey: output.scriptpubkey,\n };\n}\n\n/**\n * Get all UTXOs for a Bitcoin address.\n *\n * @param address - The Bitcoin address\n * @param apiUrl - Mempool API base URL\n * @returns Array of UTXOs sorted by value (largest first)\n */\nexport async function getAddressUtxos(\n address: string,\n apiUrl: string,\n): Promise<MempoolUTXO[]> {\n try {\n // Fetch UTXOs for the address\n const utxos = await fetchApi<\n {\n txid: string;\n vout: number;\n value: number;\n status: {\n confirmed: boolean;\n };\n }[]\n >(`${apiUrl}/address/${address}/utxo`);\n\n // Fetch scriptPubKey for the address\n const addressInfo = await fetchApi<{\n isvalid: boolean;\n scriptPubKey: string;\n }>(`${apiUrl}/v1/validate-address/${address}`);\n\n if (!addressInfo.isvalid) {\n throw new Error(\n `Invalid Bitcoin address: ${address}. Mempool API validation failed.`,\n );\n }\n\n // Sort by value (largest first) and map to our UTXO format\n const sortedUTXOs = utxos.sort((a, b) => b.value - a.value);\n\n return sortedUTXOs.map((utxo) => ({\n txid: utxo.txid,\n vout: utxo.vout,\n value: utxo.value,\n scriptPubKey: addressInfo.scriptPubKey,\n confirmed: utxo.status.confirmed,\n }));\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(\n `Failed to get UTXOs for address ${address}: ${error.message}`,\n );\n }\n throw new Error(\n `Failed to get UTXOs for address ${address}: Unknown error`,\n );\n }\n}\n\n/**\n * Get the mempool API URL for a given network.\n *\n * @param network - Bitcoin network (mainnet, testnet, signet)\n * @returns The mempool API URL\n */\nexport function getMempoolApiUrl(\n network: \"mainnet\" | \"testnet\" | \"signet\",\n): string {\n return MEMPOOL_API_URLS[network];\n}\n\n/**\n * Transaction summary from address transactions endpoint.\n */\nexport interface AddressTx {\n txid: string;\n status: {\n confirmed: boolean;\n block_height?: number;\n };\n}\n\n/**\n * Get recent transactions for a Bitcoin address.\n *\n * Returns the last 25 confirmed transactions plus any unconfirmed (mempool) transactions.\n * This is useful for checking if a specific transaction has been broadcast.\n *\n * @param address - The Bitcoin address\n * @param apiUrl - Mempool API base URL\n * @returns Array of recent transactions\n */\nexport async function getAddressTxs(\n address: string,\n apiUrl: string,\n): Promise<AddressTx[]> {\n return fetchApi<AddressTx[]>(`${apiUrl}/address/${address}/txs`);\n}\n\n/**\n * Fetches Bitcoin network fee recommendations from mempool.space API.\n *\n * @param apiUrl - Mempool API base URL\n * @returns Fee rates in sat/vbyte for different confirmation times\n * @throws Error if request fails or returns invalid data\n *\n * @see https://mempool.space/docs/api/rest#get-recommended-fees\n */\nexport async function getNetworkFees(apiUrl: string): Promise<NetworkFees> {\n const response = await fetch(`${apiUrl}/v1/fees/recommended`);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch network fees: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n typeof data.fastestFee !== \"number\" ||\n typeof data.halfHourFee !== \"number\" ||\n typeof data.hourFee !== \"number\" ||\n typeof data.economyFee !== \"number\" ||\n typeof data.minimumFee !== \"number\"\n ) {\n throw new Error(\n \"Invalid fee data structure from mempool API. Expected all fee fields to be numbers.\",\n );\n }\n\n return data as NetworkFees;\n}\n\n","/**\n * BTCVaultRegistry Contract ABI\n *\n * Minimal ABI containing only the functions needed by the SDK.\n * Full ABI is available in the vault service package.\n *\n * @module contracts/abis/BTCVaultRegistry\n */\n\n/**\n * Minimal ABI for BTCVaultRegistry contract.\n * Contains submitPeginRequest, activateVaultWithSecret, getPegInFee, and getBTCVault.\n */\nexport const BTCVaultRegistryABI = [\n {\n type: \"function\",\n name: \"submitPeginRequest\",\n inputs: [\n {\n name: \"depositor\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"depositorBtcPubKey\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"btcPopSignature\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"unsignedPrePeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorSignedPeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"vaultProvider\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"hashlock\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"htlcVout\",\n type: \"uint8\",\n internalType: \"uint8\",\n },\n {\n name: \"depositorPayoutBtcAddress\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorLamportPkHash\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n stateMutability: \"payable\",\n },\n {\n type: \"function\",\n name: \"submitPeginRequest\",\n inputs: [\n {\n name: \"depositor\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"depositorBtcPubKey\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"btcPopSignature\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"unsignedPrePeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorSignedPeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"vaultProvider\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"hashlock\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"htlcVout\",\n type: \"uint8\",\n internalType: \"uint8\",\n },\n {\n name: \"referralCode\",\n type: \"uint32\",\n internalType: \"uint32\",\n },\n {\n name: \"depositorPayoutBtcAddress\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorLamportPkHash\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n stateMutability: \"payable\",\n },\n {\n type: \"function\",\n name: \"activateVaultWithSecret\",\n inputs: [\n {\n name: \"vaultId\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"s\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"getPegInFee\",\n inputs: [\n {\n name: \"vaultProvider\",\n type: \"address\",\n internalType: \"address\",\n },\n ],\n outputs: [\n {\n name: \"totalFee\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"getBTCVault\",\n inputs: [\n {\n name: \"vaultId\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"vault\",\n type: \"tuple\",\n internalType: \"struct IBTCVaultRegistry.BTCVault\",\n components: [\n { name: \"depositor\", type: \"address\", internalType: \"address\" },\n { name: \"depositorBtcPubKey\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"depositorSignedPeginTx\", type: \"bytes\", internalType: \"bytes\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"vaultProvider\", type: \"address\", internalType: \"address\" },\n { name: \"status\", type: \"uint8\", internalType: \"enum IBTCVaultRegistry.BTCVaultStatus\" },\n { name: \"applicationEntryPoint\", type: \"address\", internalType: \"address\" },\n { name: \"universalChallengersVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"appVaultKeepersVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"offchainParamsVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"proverProgramVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"createdAt\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"verifiedAt\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"depositorLamportPkHash\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"hashlock\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"htlcVout\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"error\",\n name: \"InvalidPeginFee\",\n inputs: [\n {\n name: \"provided\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n {\n name: \"required\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n },\n {\n type: \"error\",\n name: \"InvalidSecret\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"ActivationDeadlineExpired\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"InvalidHashlock\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"DuplicateHashlock\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"CapExceeded\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"InvalidOutputIndex\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"PeginSignaturesIncomplete\",\n inputs: [],\n },\n] as const;\n","/**\n * Contract Error Handling Utilities\n *\n * Provides utilities for extracting and handling contract revert errors.\n * Maps known error selectors to user-friendly messages.\n *\n * @module contracts/errors\n */\n\n/**\n * Known contract error signatures mapped to user-friendly messages.\n *\n * Error selectors are the first 4 bytes of keccak256(error signature).\n * Example: keccak256(\"VaultAlreadyExists()\") = 0x04aabf33...\n */\nexport const CONTRACT_ERRORS: Record<string, string> = {\n // VaultAlreadyExists()\n \"0x04aabf33\":\n \"Vault already exists: This Bitcoin transaction has already been registered. \" +\n \"Please select different UTXOs or use a different amount to create a unique transaction.\",\n // ScriptPubKeyMismatch() - taproot output doesn't match expected script\n \"0x4fec082d\":\n \"Script mismatch: The Bitcoin transaction's taproot output does not match the expected vault script. \" +\n \"This may be caused by incorrect vault participants or key configuration.\",\n // InvalidBTCProofOfPossession()\n \"0x6cc363a5\":\n \"Invalid BTC proof of possession: The signature could not be verified. \" +\n \"Please ensure you're signing with the correct Bitcoin wallet.\",\n // InvalidBTCPublicKey()\n \"0x6c3f2bf6\":\n \"Invalid BTC public key: The Bitcoin public key format is invalid.\",\n // InvalidAmount()\n \"0x2c5211c6\":\n \"Invalid amount: The deposit amount is invalid or below the minimum required.\",\n // ApplicationNotRegistered()\n \"0x0405f772\":\n \"Application not registered: The application controller is not registered in the system.\",\n // InvalidProviderStatus()\n \"0x24e165cc\":\n \"Invalid provider status: The vault provider is not in a valid state to accept deposits.\",\n // ZeroAddress()\n \"0xd92e233d\":\n \"Zero address: One of the required addresses is the zero address.\",\n // BtcKeyMismatch()\n \"0x65aa7007\":\n \"BTC key mismatch: The Bitcoin public key does not match the expected key.\",\n // Unauthorized()\n \"0x82b42900\":\n \"Unauthorized: You must be the depositor or vault provider to submit this transaction.\",\n // InvalidSignature() - common signature verification error\n \"0x8baa579f\":\n \"Invalid signature: The BTC proof of possession signature could not be verified.\",\n // InvalidBtcTransaction()\n \"0x2f9d01e9\":\n \"Invalid BTC transaction: The Bitcoin transaction format is invalid.\",\n // VaultProviderNotRegistered()\n \"0x5a3c6b3e\":\n \"Vault provider not registered: The selected vault provider is not registered.\",\n // InvalidPeginFee(uint256,uint256)\n \"0x979f4518\":\n \"Invalid pegin fee: The ETH fee sent does not match the required amount. \" +\n \"This may indicate a fee rate change during the transaction.\",\n};\n\n/**\n * Extract error data from various error formats.\n *\n * Viem and wallet providers wrap errors in multiple levels. This function\n * searches through the error chain to find the revert data.\n *\n * @param error - The error object to extract data from\n * @returns The error data (e.g., \"0x04aabf33\") or undefined\n */\nexport function extractErrorData(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") return undefined;\n\n const err = error as Record<string, unknown>;\n\n // Check direct properties first\n if (typeof err.data === \"string\" && err.data.startsWith(\"0x\")) {\n return err.data;\n }\n if (typeof err.details === \"string\" && err.details.startsWith(\"0x\")) {\n return err.details;\n }\n\n // Walk the cause chain (viem wraps errors multiple levels deep)\n let current: unknown = err.cause;\n let depth = 0;\n const maxDepth = 5;\n\n while (current && typeof current === \"object\" && depth < maxDepth) {\n const cause = current as Record<string, unknown>;\n if (typeof cause.data === \"string\" && cause.data.startsWith(\"0x\")) {\n return cause.data;\n }\n current = cause.cause;\n depth++;\n }\n\n // Check error message for embedded hex error selector\n const message = typeof err.message === \"string\" ? err.message : \"\";\n const hexMatch = message.match(/\\b(0x[a-fA-F0-9]{8})\\b/);\n if (hexMatch) {\n return hexMatch[1];\n }\n\n return undefined;\n}\n\n/**\n * Get a user-friendly error message for a contract error.\n *\n * @param error - The error object from a contract call\n * @returns A user-friendly error message, or undefined if error is not recognized\n */\nexport function getContractErrorMessage(error: unknown): string | undefined {\n const errorData = extractErrorData(error);\n if (errorData) {\n // Check exact match first, then match by 4-byte selector prefix.\n // Parametric errors (e.g. InvalidPeginFee(uint256,uint256)) return\n // the selector + ABI-encoded args, so the full string won't match.\n const selector = errorData.substring(0, 10); // \"0x\" + 4 bytes\n return CONTRACT_ERRORS[errorData] ?? CONTRACT_ERRORS[selector];\n }\n return undefined;\n}\n\n/**\n * Check if an error is a known contract error.\n *\n * @param error - The error object to check\n * @returns True if the error is a known contract error\n */\nexport function isKnownContractError(error: unknown): boolean {\n const errorData = extractErrorData(error);\n if (errorData === undefined) return false;\n const selector = errorData.substring(0, 10);\n return errorData in CONTRACT_ERRORS || selector in CONTRACT_ERRORS;\n}\n\n/**\n * Handle a contract error by throwing a user-friendly error.\n *\n * This function extracts error data, maps it to a user-friendly message,\n * and throws an appropriate error. Use this in catch blocks after contract calls.\n *\n * @param error - The error from a contract call\n * @throws Always throws an error with a descriptive message\n */\nexport function handleContractError(error: unknown): never {\n // Log full error for debugging\n console.error(\"[Contract Error] Raw error:\", error);\n\n // Extract error data from the error chain\n const errorData = extractErrorData(error);\n console.error(\"[Contract Error] Extracted error data:\", errorData);\n\n // Check for known contract error signatures (exact match or 4-byte selector prefix)\n if (errorData) {\n const selector = errorData.substring(0, 10);\n const knownError = CONTRACT_ERRORS[errorData] ?? CONTRACT_ERRORS[selector];\n if (knownError) {\n console.error(\"[Contract Error] Known error:\", knownError);\n throw new Error(knownError);\n }\n }\n\n // Check for gas estimation errors or internal JSON-RPC errors\n const errorMsg = (error as Error)?.message || \"\";\n if (\n errorMsg.includes(\"gas limit too high\") ||\n errorMsg.includes(\"21000000\") ||\n errorMsg.includes(\"Internal JSON-RPC error\")\n ) {\n // If we found error data but it's not in our known list, include it\n const errorHint = errorData ? ` (error code: ${errorData})` : \"\";\n console.error(\n \"[Contract Error] Transaction rejected. Error code:\",\n errorData,\n \"Message:\",\n errorMsg,\n );\n throw new Error(\n `Transaction failed: The contract rejected this transaction${errorHint}. ` +\n \"Possible causes: (1) Vault already exists for this transaction, \" +\n \"(2) Invalid signature, (3) Unauthorized caller. \" +\n \"Please check your transaction parameters and try again.\",\n );\n }\n\n // Default: re-throw original error with better context\n if (error instanceof Error) {\n console.error(\"[Contract Error] Unhandled error:\", error.message);\n throw error;\n }\n throw new Error(`Contract call failed: ${String(error)}`);\n}\n","/**\n * Peg-in Manager - Wallet Orchestration for Peg-in Operations\n *\n * This module provides the PeginManager class that orchestrates the complete\n * peg-in flow using SDK primitives, utilities, and wallet interfaces.\n *\n * @remarks\n * PeginManager handles the peg-in flow:\n * 1. **preparePegin()** - Build Pre-PegIn HTLC, fund it, sign PegIn input\n * 2. **registerPeginOnChain()** - Submit to Ethereum contract with PoP\n * 3. *(Use {@link PayoutManager} for payout authorization signing)*\n * 4. **signAndBroadcast()** - Sign and broadcast Pre-PegIn tx to Bitcoin network\n *\n * @see {@link PayoutManager} - For Step 3: sign payout transactions\n * @see {@link buildPrePeginPsbt} - Lower-level primitive used internally\n *\n * @module managers/PeginManager\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\nimport {\n createPublicClient,\n encodeFunctionData,\n http,\n zeroAddress,\n type Address,\n type Chain,\n type Hex,\n type WalletClient,\n} from \"viem\";\n\nimport type { BitcoinWallet, Hash } from \"../../../shared/wallets\";\nimport { createTaprootScriptPathSignOptions } from \"../../../shared/wallets\";\nimport { getUtxoInfo, pushTx } from \"../clients/mempool\";\nimport { BTCVaultRegistryABI, handleContractError } from \"../contracts\";\nimport {\n buildPrePeginPsbt,\n buildPeginTxFromFundedPrePegin,\n buildPeginInputPsbt,\n extractPeginInputSignature,\n finalizePeginInputPsbt,\n SINGLE_DEPOSIT_HTLC_VOUT,\n type PrePeginParams,\n type Network,\n} from \"../primitives\";\nimport {\n ensureHexPrefix,\n isAddressFromPublicKey,\n stripHexPrefix,\n} from \"../primitives/utils/bitcoin\";\nimport {\n calculateBtcTxHash,\n fundPeginTransaction,\n getNetwork,\n getPsbtInputFields,\n selectUtxosForPegin,\n type UTXO,\n} from \"../utils\";\n\n/**\n * Configuration for the PeginManager.\n */\nexport interface PeginManagerConfig {\n /**\n * Bitcoin network to use for transactions.\n */\n btcNetwork: Network;\n\n /**\n * Bitcoin wallet for signing peg-in transactions.\n */\n btcWallet: BitcoinWallet;\n\n /**\n * Ethereum wallet for registering peg-in on-chain.\n * Uses viem's WalletClient directly for proper gas estimation.\n */\n ethWallet: WalletClient;\n\n /**\n * Ethereum chain configuration.\n * Required for proper gas estimation in contract calls.\n */\n ethChain: Chain;\n\n /**\n * Vault contract addresses.\n */\n vaultContracts: {\n /**\n * BTCVaultRegistry contract address on Ethereum.\n */\n btcVaultRegistry: Address;\n };\n\n /**\n * Mempool API URL for fetching UTXO data and broadcasting transactions.\n * Use MEMPOOL_API_URLS constant for standard mempool.space URLs, or provide\n * a custom URL if running your own mempool instance.\n */\n mempoolApiUrl: string;\n}\n\n/**\n * Parameters for the pegin flow (pre-pegin + pegin transactions).\n */\nexport interface PreparePeginParams {\n /**\n * Amount to peg in (in satoshis).\n */\n amount: bigint;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n vaultKeeperBtcPubkeys: readonly string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n universalChallengerBtcPubkeys: readonly string[];\n\n /**\n * CSV timelock in blocks for the PegIn vault output.\n */\n timelockPegin: number;\n\n /**\n * CSV timelock in blocks for the Pre-PegIn HTLC refund path.\n */\n timelockRefund: number;\n\n /**\n * SHA256 hash commitment(s) for the HTLC (64 hex chars = 32 bytes each).\n * Generated by the depositor as H = SHA256(secret).\n * For single deposits, pass a single-element array.\n */\n hashlocks: readonly string[];\n\n /**\n * Protocol fee rate in sat/vB from the contract offchain params.\n * Used by WASM for computing depositorClaimValue and min pegin fee.\n */\n protocolFeeRate: bigint;\n\n /**\n * Mempool fee rate in sat/vB for funding the Pre-PegIn transaction.\n * Used for UTXO selection and change calculation.\n */\n mempoolFeeRate: number;\n\n /**\n * M in M-of-N council multisig (from contract params).\n */\n councilQuorum: number;\n\n /**\n * N in M-of-N council multisig (from contract params).\n */\n councilSize: number;\n\n /**\n * Available UTXOs from the depositor's wallet for funding the Pre-PegIn transaction.\n */\n availableUTXOs: readonly UTXO[];\n\n /**\n * Bitcoin address for receiving change from the Pre-PegIn transaction.\n */\n changeAddress: string;\n}\n\n/**\n * Result of preparing a pegin.\n */\nexport interface PreparePeginResult {\n /**\n * Funded but unsigned Pre-PegIn transaction hex.\n * Sign and broadcast this AFTER registering on Ethereum.\n */\n fundedPrePeginTxHex: string;\n\n /**\n * Pre-PegIn HTLC value in satoshis (amount the UTXOs cover).\n */\n htlcValue: bigint;\n\n /**\n * PegIn transaction hex with depositor's HTLC leaf 0 signature embedded in the PSBT.\n * Submit the extracted signature to the vault provider.\n */\n signedPeginInputPsbtHex: string;\n\n /**\n * Depositor's Schnorr signature over PegIn input 0 (HTLC leaf 0), 128 hex chars.\n * This is submitted to the contract via the VP's signPeginInput batch.\n */\n peginInputSignature: string;\n\n /**\n * Vault script pubkey hex — used in the ETH registration call.\n */\n vaultScriptPubKey: string;\n\n /**\n * Funded Pre-PegIn transaction ID.\n */\n prePeginTxid: string;\n\n /**\n * PegIn transaction hex. Pass to registerPeginOnChain as `depositorSignedPeginTx`\n * so the contract computes the correct vault ID from the pegin txid.\n */\n peginTxHex: string;\n\n /**\n * PegIn transaction ID (stable — signing does not change it).\n */\n peginTxid: string;\n\n /**\n * UTXOs selected to fund the Pre-PegIn transaction.\n */\n selectedUTXOs: UTXO[];\n\n /**\n * Transaction fee in satoshis.\n */\n fee: bigint;\n\n /**\n * Change amount in satoshis (if any).\n */\n changeAmount: bigint;\n}\n\n\n/**\n * Parameters for signing and broadcasting a transaction.\n */\nexport interface SignAndBroadcastParams {\n /**\n * Funded Pre-PegIn transaction hex from preparePegin().\n */\n fundedPrePeginTxHex: string;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix.\n * Required for Taproot signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * Parameters for registering a peg-in on Ethereum.\n */\nexport interface RegisterPeginParams {\n /**\n * Depositor's BTC public key (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix.\n */\n depositorBtcPubkey: string;\n\n /**\n * Unsigned Pre-PegIn transaction hex (submitted to contract for data availability).\n */\n unsignedPrePeginTx: string;\n\n /**\n * Depositor-signed PegIn transaction hex (submitted to contract; vault ID derived from this).\n */\n depositorSignedPeginTx: string;\n\n /**\n * Vault provider's Ethereum address.\n */\n vaultProvider: Address;\n\n /**\n * SHA256 hashlock for HTLC activation (bytes32 hex with 0x prefix).\n */\n hashlock: Hex;\n\n /**\n * Optional callback invoked after PoP signing completes but before ETH transaction.\n */\n onPopSigned?: () => void | Promise<void>;\n\n /**\n * Depositor's BTC payout address (e.g. bc1p..., bc1q...).\n * Converted to scriptPubKey internally via bitcoinjs-lib.\n *\n * If omitted, defaults to the connected BTC wallet's address\n * via `btcWallet.getAddress()`.\n */\n depositorPayoutBtcAddress?: string;\n\n /** Keccak256 hash of the depositor's Lamport public key (bytes32) */\n depositorLamportPkHash: Hex;\n\n /**\n * Pre-signed BTC PoP signature (hex with 0x prefix).\n * When provided, the BTC wallet signing step is skipped and this signature is used directly.\n * Useful for multi-vault deposits where PoP only needs to be signed once.\n */\n preSignedBtcPopSignature?: Hex;\n\n /**\n * SHA-256 hash of the depositor's secret (bytes32).\n * Required for the new peg-in flow deposits.\n * TODO: Wire into submitPeginRequest contract call when contract ABI is updated to support the new peg-in flow.\n */\n depositorSecretHash?: Hex;\n}\n\n/**\n * Result of registering a peg-in on Ethereum.\n */\nexport interface RegisterPeginResult {\n /**\n * Ethereum transaction hash for the peg-in registration.\n */\n ethTxHash: Hash;\n\n /**\n * Vault identifier used in the BTCVaultRegistry contract.\n * This is the Bitcoin transaction hash with 0x prefix for Ethereum compatibility.\n * Corresponds to btcTxHash from PeginResult, but formatted as Hex with '0x' prefix.\n */\n vaultId: Hex;\n\n /**\n * The BTC PoP signature used for this registration (hex with 0x prefix).\n * Returned so callers can reuse it for subsequent pegins without re-signing.\n */\n btcPopSignature: Hex;\n}\n\n/**\n * Manager for orchestrating peg-in operations.\n *\n * This manager provides a high-level API for creating peg-in transactions\n * by coordinating between SDK primitives, utilities, and wallet interfaces.\n *\n * @remarks\n * The complete peg-in flow consists of 4 steps:\n *\n * | Step | Method | Description |\n * |------|--------|-------------|\n * | 1 | {@link preparePegin} | Build Pre-PegIn HTLC, fund it, sign PegIn input |\n * | 2 | {@link registerPeginOnChain} | Submit to Ethereum contract with PoP |\n * | 3 | {@link PayoutManager} | Sign BOTH payout authorizations |\n * | 4 | {@link signAndBroadcast} | Sign and broadcast Pre-PegIn tx to Bitcoin network |\n *\n * **Important:** Step 3 uses {@link PayoutManager}, not this class. After step 2,\n * the vault provider prepares 3 transactions per claimer:\n * - `claim_tx` - Claim transaction\n * - `assert_tx` - Assert transaction\n * - `payout_tx` - Payout transaction\n *\n * You must sign the Payout transaction for each claimer:\n * - {@link PayoutManager.signPayoutTransaction} - uses assert_tx as input reference\n *\n * Submit all signatures to the vault provider before proceeding to step 4.\n *\n * @see {@link PayoutManager} - Required for Step 3 (payout authorization)\n * @see {@link buildPrePeginPsbt} - Lower-level primitive for custom implementations\n * @see {@link https://github.com/babylonlabs-io/babylon-toolkit/blob/main/packages/babylon-ts-sdk/docs/quickstart/managers.md | Managers Quickstart}\n */\nexport class PeginManager {\n private readonly config: PeginManagerConfig;\n\n /**\n * Creates a new PeginManager instance.\n *\n * @param config - Manager configuration including wallets and contract addresses\n */\n constructor(config: PeginManagerConfig) {\n this.config = config;\n }\n\n /**\n * Prepares a peg-in by building the Pre-PegIn HTLC transaction,\n * funding it, constructing the PegIn transaction, and signing the PegIn input.\n *\n * This method orchestrates the following steps:\n * 1. Get depositor BTC public key from wallet\n * 2. Build unfunded Pre-PegIn transaction (HTLC output) using primitives\n * 3. Select UTXOs to cover the HTLC value\n * 4. Fund the Pre-PegIn transaction\n * 5. Derive the PegIn transaction from the funded Pre-PegIn txid\n * 6. Build PSBT for signing the PegIn input (HTLC leaf 0)\n * 7. Sign via BTC wallet and extract depositor signature\n *\n * The returned `fundedPrePeginTxHex` is funded but unsigned (inputs unsigned).\n * Use `signAndBroadcast()` AFTER registering on Ethereum to broadcast it.\n *\n * @param params - Pegin parameters including amount, HTLC params, UTXOs\n * @returns Pegin result with funded Pre-PegIn tx, signed PegIn input, and signatures\n * @throws Error if wallet operations fail or insufficient funds\n */\n async preparePegin(\n params: PreparePeginParams,\n ): Promise<PreparePeginResult> {\n // Step 1: Get depositor BTC public key from wallet\n const depositorBtcPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n // Convert 33-byte compressed (66 chars) to 32-byte x-only (64 chars) if needed\n const depositorBtcPubkey =\n depositorBtcPubkeyRaw.length === 66\n ? depositorBtcPubkeyRaw.slice(2)\n : depositorBtcPubkeyRaw;\n\n const vaultProviderBtcPubkey = stripHexPrefix(params.vaultProviderBtcPubkey);\n const vaultKeeperBtcPubkeys = params.vaultKeeperBtcPubkeys.map(stripHexPrefix);\n const universalChallengerBtcPubkeys =\n params.universalChallengerBtcPubkeys.map(stripHexPrefix);\n\n if (params.hashlocks.length !== 1) {\n throw new Error(\n \"hashlocks must contain exactly one entry (batched deposits not yet supported)\",\n );\n }\n\n const numLocalChallengers = vaultKeeperBtcPubkeys.length;\n\n const prePeginParams: PrePeginParams = {\n depositorPubkey: depositorBtcPubkey,\n vaultProviderPubkey: vaultProviderBtcPubkey,\n vaultKeeperPubkeys: vaultKeeperBtcPubkeys,\n universalChallengerPubkeys: universalChallengerBtcPubkeys,\n hashlocks: params.hashlocks,\n timelockRefund: params.timelockRefund,\n pegInAmount: params.amount,\n feeRate: params.protocolFeeRate,\n numLocalChallengers,\n councilQuorum: params.councilQuorum,\n councilSize: params.councilSize,\n network: this.config.btcNetwork,\n };\n\n // Step 2: Build unfunded Pre-PegIn transaction (HTLC output, no inputs)\n const prePeginResult = await buildPrePeginPsbt(prePeginParams);\n\n // Step 3: Select UTXOs to cover ALL unfunded tx outputs (HTLC + CPFP anchor)\n // fundPeginTransaction copies all WASM outputs, so UTXO selection must\n // account for their total value, not just the HTLC output.\n const utxoSelection = selectUtxosForPegin(\n [...params.availableUTXOs],\n prePeginResult.totalOutputValue,\n params.mempoolFeeRate,\n );\n\n // Step 4: Fund the Pre-PegIn transaction with selected UTXOs\n const network = getNetwork(this.config.btcNetwork);\n const fundedPrePeginTxHex = fundPeginTransaction({\n unfundedTxHex: prePeginResult.psbtHex,\n selectedUTXOs: utxoSelection.selectedUTXOs,\n changeAddress: params.changeAddress,\n changeAmount: utxoSelection.changeAmount,\n network,\n });\n\n // Compute the funded Pre-PegIn txid for reference\n const prePeginTxid = stripHexPrefix(calculateBtcTxHash(fundedPrePeginTxHex));\n\n // Step 5: Derive the PegIn transaction from the funded Pre-PegIn tx\n const peginTxResult = await buildPeginTxFromFundedPrePegin({\n prePeginParams,\n timelockPegin: params.timelockPegin,\n fundedPrePeginTxHex,\n htlcVout: SINGLE_DEPOSIT_HTLC_VOUT,\n });\n\n // Step 6: Build PSBT for depositor to sign PegIn input 0 (HTLC hashlock leaf)\n const peginInputPsbtResult = await buildPeginInputPsbt({\n peginTxHex: peginTxResult.txHex,\n fundedPrePeginTxHex,\n depositorPubkey: depositorBtcPubkey,\n vaultProviderPubkey: vaultProviderBtcPubkey,\n vaultKeeperPubkeys: vaultKeeperBtcPubkeys,\n universalChallengerPubkeys: universalChallengerBtcPubkeys,\n hashlock: params.hashlocks[0],\n timelockRefund: params.timelockRefund,\n network: this.config.btcNetwork,\n });\n\n // Step 7: Sign the PegIn input PSBT via BTC wallet (Taproot script-path spend)\n const signedPeginInputPsbtHex = await this.config.btcWallet.signPsbt(\n peginInputPsbtResult.psbtHex,\n createTaprootScriptPathSignOptions(depositorBtcPubkeyRaw, 1),\n );\n\n // Extract the depositor's Schnorr signature from the signed PSBT\n const peginInputSignature = extractPeginInputSignature(\n signedPeginInputPsbtHex,\n depositorBtcPubkey,\n );\n\n // Finalize the PSBT so the witness stack contains [sig, script, controlBlock],\n // then extract the transaction hex. This is the depositor-signed PegIn tx that\n // vaultd expects when verifying the depositor signature on-chain.\n const depositorSignedPeginTxHex = finalizePeginInputPsbt(signedPeginInputPsbtHex);\n\n return {\n fundedPrePeginTxHex,\n htlcValue: prePeginResult.htlcValue,\n signedPeginInputPsbtHex,\n peginInputSignature,\n vaultScriptPubKey: peginTxResult.vaultScriptPubKey,\n peginTxHex: depositorSignedPeginTxHex,\n prePeginTxid,\n peginTxid: peginTxResult.txid,\n selectedUTXOs: utxoSelection.selectedUTXOs,\n fee: utxoSelection.fee,\n changeAmount: utxoSelection.changeAmount,\n };\n }\n\n /**\n * Signs and broadcasts a funded peg-in transaction to the Bitcoin network.\n *\n * This method:\n * 1. Parses the funded transaction hex\n * 2. Fetches UTXO data from mempool for each input\n * 3. Creates a PSBT with proper witnessUtxo/tapInternalKey\n * 4. Signs via btcWallet.signPsbt()\n * 5. Finalizes and extracts the transaction\n * 6. Broadcasts via mempool API\n *\n * @param params - Transaction hex and depositor public key\n * @returns The broadcasted Bitcoin transaction ID\n * @throws Error if signing or broadcasting fails\n */\n async signAndBroadcast(params: SignAndBroadcastParams): Promise<string> {\n const { fundedPrePeginTxHex, depositorBtcPubkey } = params;\n\n // Step 1: Parse the funded transaction\n const cleanHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const tx = Transaction.fromHex(cleanHex);\n\n if (tx.ins.length === 0) {\n throw new Error(\"Transaction has no inputs\");\n }\n\n // Step 2: Create PSBT and add inputs with UTXO data from mempool\n const psbt = new Psbt();\n psbt.setVersion(tx.version);\n psbt.setLocktime(tx.locktime);\n\n // Strip 0x prefix if present before converting to Buffer\n const cleanPubkey = depositorBtcPubkey.startsWith(\"0x\")\n ? depositorBtcPubkey.slice(2)\n : depositorBtcPubkey;\n // Validate x-only pubkey length and format (32 bytes = 64 hex chars)\n if (cleanPubkey.length !== 64 || !/^[0-9a-fA-F]+$/.test(cleanPubkey)) {\n throw new Error(\n \"Invalid depositorBtcPubkey: expected 64 hex characters (x-only pubkey)\",\n );\n }\n const publicKeyNoCoord = Buffer.from(cleanPubkey, \"hex\");\n if (publicKeyNoCoord.length !== 32) {\n throw new Error(\n `Invalid depositorBtcPubkey length: expected 32 bytes, got ${publicKeyNoCoord.length}`,\n );\n }\n const apiUrl = this.config.mempoolApiUrl;\n\n // Fetch all UTXO data in parallel for better performance\n const utxoDataPromises = tx.ins.map((input) => {\n const txid = Buffer.from(input.hash).reverse().toString(\"hex\");\n const vout = input.index;\n return getUtxoInfo(txid, vout, apiUrl).then((utxoData) => ({\n input,\n utxoData,\n txid,\n vout,\n }));\n });\n\n const inputsWithUtxoData = await Promise.all(utxoDataPromises);\n\n // Add inputs with proper PSBT fields based on script type\n for (const { input, utxoData, txid, vout } of inputsWithUtxoData) {\n const psbtInputFields = getPsbtInputFields(\n {\n txid,\n vout,\n value: utxoData.value,\n scriptPubKey: utxoData.scriptPubKey,\n },\n publicKeyNoCoord,\n );\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n ...psbtInputFields,\n });\n }\n\n // Step 3: Add outputs\n for (const output of tx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n // Step 4: Sign PSBT via wallet\n const signedPsbtHex = await this.config.btcWallet.signPsbt(psbt.toHex());\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n\n // Step 5: Finalize and extract transaction\n try {\n signedPsbt.finalizeAllInputs();\n } catch (e) {\n // Some wallets (e.g. UniSat, OKX) auto-finalize PSBTs before returning them.\n // Attempting to finalize again throws, which is expected and safe to skip —\n // but verify the wallet actually finalized all inputs.\n const allFinalized = signedPsbt.data.inputs.every(\n (inp) => inp.finalScriptWitness || inp.finalScriptSig,\n );\n if (!allFinalized) {\n throw new Error(\n `PSBT finalization failed and wallet did not auto-finalize: ${e}`,\n );\n }\n }\n\n const signedTxHex = signedPsbt.extractTransaction().toHex();\n\n // Step 6: Broadcast to Bitcoin network\n const btcTxid = await pushTx(signedTxHex, apiUrl);\n\n return btcTxid;\n }\n\n /**\n * Registers a peg-in on Ethereum by calling the BTCVaultRegistry contract.\n *\n * This method:\n * 1. Gets depositor ETH address from wallet\n * 2. Creates proof of possession (BTC signature of ETH address)\n * 3. Checks if vault already exists (pre-flight check)\n * 4. Encodes the contract call using viem\n * 5. Estimates gas (catches contract errors early with proper revert reasons)\n * 6. Sends transaction with pre-estimated gas via ethWallet.sendTransaction()\n *\n * @param params - Registration parameters including BTC pubkey and unsigned tx\n * @returns Result containing Ethereum transaction hash and vault ID\n * @throws Error if signing or transaction fails\n * @throws Error if vault already exists\n * @throws Error if contract simulation fails (e.g., invalid signature, unauthorized)\n */\n async registerPeginOnChain(\n params: RegisterPeginParams,\n ): Promise<RegisterPeginResult> {\n const {\n depositorBtcPubkey,\n unsignedPrePeginTx,\n depositorSignedPeginTx,\n vaultProvider,\n hashlock,\n onPopSigned,\n depositorPayoutBtcAddress,\n depositorLamportPkHash,\n preSignedBtcPopSignature,\n } = params;\n\n // Step 1: Get depositor ETH address (from wallet account)\n if (!this.config.ethWallet.account) {\n throw new Error(\"Ethereum wallet account not found\");\n }\n const depositorEthAddress = this.config.ethWallet.account.address;\n\n // Step 2: Create proof of possession (or reuse pre-signed one)\n const btcPopSignature = await this.resolvePopSignature(\n depositorEthAddress,\n preSignedBtcPopSignature,\n );\n\n if (onPopSigned) {\n await onPopSigned();\n }\n\n // Step 3: Format parameters for contract call\n const depositorBtcPubkeyHex = ensureHexPrefix(depositorBtcPubkey);\n const unsignedPrePeginTxHex = ensureHexPrefix(unsignedPrePeginTx);\n const depositorSignedPeginTxHex = ensureHexPrefix(depositorSignedPeginTx);\n\n const payoutScriptPubKey = await this.resolvePayoutScriptPubKey(\n depositorPayoutBtcAddress,\n );\n\n // Step 4: Calculate vault ID from depositorSignedPeginTx and check if it already exists\n const vaultId = calculateBtcTxHash(depositorSignedPeginTxHex);\n const exists = await this.checkVaultExists(vaultId);\n\n if (exists) {\n throw new Error(\n `Vault already exists for this transaction (ID: ${vaultId}). ` +\n `Vault IDs are deterministically derived from the unsigned Bitcoin transaction, so using the same UTXOs and amount will always produce the same vault. ` +\n `To create a new vault, please use different UTXOs or a different amount to generate a unique transaction.`,\n );\n }\n\n // Step 5: Query required pegin fee from the contract\n const publicClient = createPublicClient({\n chain: this.config.ethChain,\n transport: http(),\n });\n\n let peginFee: bigint;\n try {\n peginFee = (await publicClient.readContract({\n address: this.config.vaultContracts.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n } catch {\n throw new Error(\n \"Failed to query pegin fee from the contract. \" +\n \"Please check your network connection and that the contract address is correct.\",\n );\n }\n\n // Step 6: Encode the contract call data\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequest\",\n args: [\n depositorEthAddress,\n depositorBtcPubkeyHex,\n btcPopSignature,\n unsignedPrePeginTxHex,\n depositorSignedPeginTxHex,\n vaultProvider,\n hashlock,\n SINGLE_DEPOSIT_HTLC_VOUT,\n payoutScriptPubKey,\n depositorLamportPkHash,\n ],\n });\n\n // Step 7: Estimate gas first to catch contract errors before showing wallet popup\n // This ensures users see actual contract revert reasons instead of gas errors\n // The gas estimate is then passed to sendTransaction to avoid double estimation\n let gasEstimate: bigint;\n try {\n gasEstimate = await publicClient.estimateGas({\n to: this.config.vaultContracts.btcVaultRegistry,\n data: callData,\n value: peginFee,\n account: this.config.ethWallet.account.address,\n });\n } catch (error) {\n // Estimation failed - handle contract error with actual revert reason\n handleContractError(error);\n }\n\n // Step 8: Submit peg-in request to contract (estimation passed)\n try {\n // Send transaction with pre-estimated gas to skip internal estimation\n // Note: viem's sendTransaction uses `gas`, not `gasLimit`\n const ethTxHash = await this.config.ethWallet.sendTransaction({\n to: this.config.vaultContracts.btcVaultRegistry,\n data: callData,\n value: peginFee,\n account: this.config.ethWallet.account,\n chain: this.config.ethChain,\n gas: gasEstimate,\n });\n\n return {\n ethTxHash,\n vaultId,\n btcPopSignature,\n };\n } catch (error) {\n // Use proper error handler for better error messages\n handleContractError(error);\n }\n }\n\n /**\n * Check if a vault already exists for a given vault ID.\n *\n * @param vaultId - The Bitcoin transaction hash (vault ID)\n * @returns True if vault exists, false otherwise\n */\n private async checkVaultExists(vaultId: Hex): Promise<boolean> {\n try {\n // Create a public client to read from the contract\n const publicClient = createPublicClient({\n chain: this.config.ethChain,\n transport: http(),\n });\n\n const vault = (await publicClient.readContract({\n address: this.config.vaultContracts.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getBTCVault\",\n args: [vaultId],\n })) as { depositor: Address };\n\n // If depositor is not zero address, vault exists\n return vault.depositor !== zeroAddress;\n } catch {\n // If reading fails, assume vault doesn't exist and let contract handle it\n return false;\n }\n }\n\n /**\n * Resolve the BTC payout address to a scriptPubKey hex for the contract.\n *\n * If a payout address is provided, converts it directly.\n * If omitted, uses the wallet's address and validates it against the\n * wallet's public key to guard against a compromised wallet provider.\n */\n private async resolvePayoutScriptPubKey(\n depositorPayoutBtcAddress?: string,\n ): Promise<Hex> {\n let address: string;\n\n if (depositorPayoutBtcAddress) {\n address = depositorPayoutBtcAddress;\n } else {\n address = await this.config.btcWallet.getAddress();\n const walletPubkey = await this.config.btcWallet.getPublicKeyHex();\n if (\n !isAddressFromPublicKey(\n address,\n walletPubkey,\n this.config.btcNetwork,\n )\n ) {\n throw new Error(\n \"The BTC address from your wallet does not match the wallet's public key. \" +\n \"Please ensure your wallet is using a supported address type (Taproot or Native SegWit).\",\n );\n }\n }\n\n const network = getNetwork(this.config.btcNetwork);\n try {\n return `0x${bitcoin.address.toOutputScript(address, network).toString(\"hex\")}` as Hex;\n } catch {\n throw new Error(\n `Invalid BTC payout address: \"${address}\". ` +\n `Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`,\n );\n }\n }\n\n /**\n * Resolve or create a BTC Proof-of-Possession signature.\n *\n * Reuses a pre-signed signature when provided (e.g. multi-vault deposits),\n * otherwise signs a BIP-322 message with the BTC wallet.\n */\n private async resolvePopSignature(\n depositorEthAddress: Address,\n preSignedBtcPopSignature?: Hex,\n ): Promise<Hex> {\n if (preSignedBtcPopSignature) {\n return preSignedBtcPopSignature;\n }\n\n // Message format matches BTCProofOfPossession.sol buildMessage()\n const verifyingContract = this.config.vaultContracts.btcVaultRegistry;\n const popMessage = `${depositorEthAddress.toLowerCase()}:${this.config.ethChain.id}:pegin:${verifyingContract.toLowerCase()}`;\n const btcPopSignatureRaw = await this.config.btcWallet.signMessage(\n popMessage,\n \"bip322-simple\",\n );\n\n // BTC wallets return base64, Ethereum contracts expect hex\n if (btcPopSignatureRaw.startsWith(\"0x\")) {\n return btcPopSignatureRaw as Hex;\n }\n const signatureBytes = Buffer.from(btcPopSignatureRaw, \"base64\");\n return `0x${signatureBytes.toString(\"hex\")}` as Hex;\n }\n\n /**\n * Gets the configured Bitcoin network.\n *\n * @returns The Bitcoin network (mainnet, testnet, signet, regtest)\n */\n getNetwork(): Network {\n return this.config.btcNetwork;\n }\n\n /**\n * Gets the configured BTCVaultRegistry contract address.\n *\n * @returns The Ethereum address of the BTCVaultRegistry contract\n */\n getVaultContractAddress(): Address {\n return this.config.vaultContracts.btcVaultRegistry;\n }\n}\n","/**\n * Payout Manager\n *\n * High-level manager that orchestrates the payout signing flow by coordinating\n * SDK primitives ({@link buildPayoutPsbt}, {@link extractPayoutSignature})\n * with a user-provided Bitcoin wallet.\n *\n * The Payout transaction references the Assert transaction (input 1).\n *\n * @see {@link PeginManager} - For Steps 1, 2, and 4 of peg-in flow\n * @see {@link buildPayoutPsbt} - Lower-level primitive for custom implementations\n * @see {@link extractPayoutSignature} - Extract signatures from signed PSBTs\n *\n * @module managers/PayoutManager\n */\n\nimport type {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../shared/wallets\";\nimport { createTaprootScriptPathSignOptions } from \"../../../shared/wallets\";\nimport {\n buildPayoutPsbt,\n extractPayoutSignature,\n validateWalletPubkey,\n type Network,\n} from \"../primitives\";\n\n/**\n * Configuration for the PayoutManager.\n */\nexport interface PayoutManagerConfig {\n /**\n * Bitcoin network to use for transactions.\n */\n network: Network;\n\n /**\n * Bitcoin wallet for signing payout transactions.\n */\n btcWallet: BitcoinWallet;\n}\n\n/**\n * Base parameters shared by both payout transaction types.\n */\ninterface SignPayoutBaseParams {\n /**\n * Peg-in transaction hex.\n * The original transaction that created the vault output being spent.\n */\n peginTxHex: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex).\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex).\n */\n vaultKeeperBtcPubkeys: string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex).\n */\n universalChallengerBtcPubkeys: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex).\n * This should be the public key that was used when creating the vault,\n * as stored on-chain. If not provided, will be fetched from the wallet.\n */\n depositorBtcPubkey?: string;\n}\n\n/**\n * Parameters for signing a Payout transaction.\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface SignPayoutParams extends SignPayoutBaseParams {\n /**\n * Payout transaction hex (unsigned).\n * This is the transaction from the vault provider that needs depositor signature.\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex.\n * Payout input 1 references Assert output 0.\n */\n assertTxHex: string;\n}\n\n/**\n * Result of signing a payout transaction.\n */\nexport interface PayoutSignatureResult {\n /**\n * 64-byte Schnorr signature (128 hex characters).\n */\n signature: string;\n\n /**\n * Depositor's BTC public key used for signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * High-level manager for payout transaction signing.\n *\n * @remarks\n * After registering your peg-in on Ethereum (Step 2), the vault provider prepares\n * claim/payout transaction pairs. You must sign each payout transaction using this\n * manager and submit the signatures to the vault provider's RPC API.\n *\n * **What happens internally:**\n * 1. Validates your wallet's public key matches the vault's depositor\n * 2. Builds an unsigned PSBT with taproot script path spend info\n * 3. Signs input 0 (the vault UTXO) with your wallet\n * 4. Extracts the 64-byte Schnorr signature\n *\n * **Note:** The payout transaction has 2 inputs. PayoutManager only signs input 0\n * (from the peg-in tx). Input 1 (from the assert tx) is signed by the vault provider.\n *\n * @see {@link PeginManager} - For the complete peg-in flow context\n * @see {@link buildPayoutPsbt} - Lower-level primitive used internally\n * @see {@link extractPayoutSignature} - Signature extraction primitive\n */\nexport class PayoutManager {\n private readonly config: PayoutManagerConfig;\n\n /**\n * Creates a new PayoutManager instance.\n *\n * @param config - Manager configuration including wallet\n */\n constructor(config: PayoutManagerConfig) {\n this.config = config;\n }\n\n /**\n * Signs a Payout transaction and extracts the Schnorr signature.\n *\n * Flow:\n * 1. Vault provider submits Claim transaction\n * 2. Claimer submits Assert transaction to prove validity\n * 3. Payout can be executed (references Assert tx)\n *\n * This method orchestrates the following steps:\n * 1. Get wallet's public key and convert to x-only format\n * 2. Validate wallet pubkey matches on-chain depositor pubkey (if provided)\n * 3. Build unsigned PSBT using primitives\n * 4. Sign PSBT via btcWallet.signPsbt()\n * 5. Extract 64-byte Schnorr signature using primitives\n *\n * The returned signature can be submitted to the vault provider API.\n *\n * @param params - Payout signing parameters\n * @returns Signature result with 64-byte Schnorr signature and depositor pubkey\n * @throws Error if wallet pubkey doesn't match depositor pubkey\n * @throws Error if wallet operations fail or signature extraction fails\n */\n async signPayoutTransaction(\n params: SignPayoutParams,\n ): Promise<PayoutSignatureResult> {\n // Validate wallet pubkey matches depositor and get both formats\n const walletPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n const { depositorPubkey } = validateWalletPubkey(\n walletPubkeyRaw,\n params.depositorBtcPubkey,\n );\n\n // Build unsigned PSBT for Payout (uses Assert tx)\n const payoutPsbt = await buildPayoutPsbt({\n payoutTxHex: params.payoutTxHex,\n peginTxHex: params.peginTxHex,\n assertTxHex: params.assertTxHex,\n depositorBtcPubkey: depositorPubkey,\n vaultProviderBtcPubkey: params.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: params.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: params.universalChallengerBtcPubkeys,\n timelockPegin: params.timelockPegin,\n network: this.config.network,\n });\n\n // Sign PSBT via wallet (Taproot script-path spend, input 0 only)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n createTaprootScriptPathSignOptions(walletPubkeyRaw, 1),\n );\n\n // Extract Schnorr signature\n const signature = extractPayoutSignature(signedPsbtHex, depositorPubkey);\n\n return {\n signature,\n depositorBtcPubkey: depositorPubkey,\n };\n }\n\n /**\n * Gets the configured Bitcoin network.\n *\n * @returns The Bitcoin network (mainnet, testnet, signet, regtest)\n */\n getNetwork(): Network {\n return this.config.network;\n }\n\n /**\n * Checks if the wallet supports batch signing (signPsbts).\n *\n * @returns true if batch signing is supported\n */\n supportsBatchSigning(): boolean {\n return typeof this.config.btcWallet.signPsbts === \"function\";\n }\n\n /**\n * Batch signs multiple payout transactions (1 per claimer).\n * This allows signing all transactions with a single wallet interaction.\n *\n * @param transactions - Array of payout params to sign\n * @returns Array of signature results matching input order\n * @throws Error if wallet doesn't support batch signing\n * @throws Error if any signing operation fails\n */\n async signPayoutTransactionsBatch(\n transactions: SignPayoutParams[],\n ): Promise<\n Array<{\n payoutSignature: string;\n depositorBtcPubkey: string;\n }>\n > {\n if (!this.supportsBatchSigning()) {\n throw new Error(\n \"Wallet does not support batch signing (signPsbts method not available)\",\n );\n }\n\n // Get wallet pubkey once\n const walletPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n\n // Build all PSBTs (1 per claimer)\n const psbtsToSign: string[] = [];\n const signOptions: SignPsbtOptions[] = [];\n const depositorPubkeys: string[] = [];\n\n for (const tx of transactions) {\n // Validate wallet pubkey matches depositor\n const { depositorPubkey } = validateWalletPubkey(\n walletPubkeyRaw,\n tx.depositorBtcPubkey,\n );\n depositorPubkeys.push(depositorPubkey);\n\n // Build Payout PSBT\n const payoutPsbt = await buildPayoutPsbt({\n payoutTxHex: tx.payoutTxHex,\n peginTxHex: tx.peginTxHex,\n assertTxHex: tx.assertTxHex,\n depositorBtcPubkey: depositorPubkey,\n vaultProviderBtcPubkey: tx.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: tx.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: tx.universalChallengerBtcPubkeys,\n timelockPegin: tx.timelockPegin,\n network: this.config.network,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push(createTaprootScriptPathSignOptions(walletPubkeyRaw, 1));\n }\n\n // Batch sign all PSBTs with single wallet interaction\n const signedPsbts = await this.config.btcWallet.signPsbts!(\n psbtsToSign,\n signOptions,\n );\n\n // Validate that wallet returned the expected number of signed PSBTs\n if (signedPsbts.length !== transactions.length) {\n throw new Error(\n `Expected ${transactions.length} signed PSBTs but received ${signedPsbts.length}`,\n );\n }\n\n // Extract signatures from signed PSBTs\n const results: Array<{\n payoutSignature: string;\n depositorBtcPubkey: string;\n }> = [];\n\n for (let i = 0; i < transactions.length; i++) {\n const depositorPubkey = depositorPubkeys[i];\n const payoutSignature = extractPayoutSignature(\n signedPsbts[i],\n depositorPubkey,\n );\n\n results.push({\n payoutSignature,\n depositorBtcPubkey: depositorPubkey,\n });\n }\n\n return results;\n }\n}\n"],"names":["selectUtxosForPegin","availableUTXOs","peginAmount","feeRate","validUTXOs","utxo","script","Buffer","bitcoinScript","sortedUTXOs","a","b","selectedUTXOs","accumulatedValue","estimatedFee","inputSize","P2TR_INPUT_SIZE","outputSize","MAX_NON_LEGACY_OUTPUT_SIZE","baseTxSize","TX_BUFFER_SIZE_OVERHEAD","rateBasedTxBufferFee","DUST_THRESHOLD","changeOutputFee","finalChangeAmount","shouldAddChangeOutput","changeAmount","getDustThreshold","BTC_DUST_SAT","calculateBtcTxHash","txHex","cleanHex","Transaction","createSplitTransaction","inputs","outputs","network","output","btcNetwork","getNetwork","tx","input","txidBuffer","outputUtxos","i","outputScript","bitcoinAddress","error","txid","createSplitTransactionPsbt","unsignedTxHex","publicKeyNoCoord","psbt","Psbt","expectedTxid","expectedVout","inputScript","witnessUtxo","BitcoinScriptType","getScriptType","scriptPubKey","length","getPsbtInputFields","type","MEMPOOL_API_URLS","fetchApi","url","options","response","errorText","contentType","pushTx","apiUrl","message","getTxInfo","getTxHex","getUtxoInfo","vout","txInfo","getAddressUtxos","address","utxos","addressInfo","getMempoolApiUrl","getAddressTxs","getNetworkFees","data","BTCVaultRegistryABI","CONTRACT_ERRORS","extractErrorData","err","current","depth","maxDepth","cause","hexMatch","getContractErrorMessage","errorData","selector","isKnownContractError","handleContractError","knownError","errorMsg","errorHint","PeginManager","config","__publicField","params","depositorBtcPubkeyRaw","depositorBtcPubkey","vaultProviderBtcPubkey","stripHexPrefix","vaultKeeperBtcPubkeys","universalChallengerBtcPubkeys","numLocalChallengers","prePeginParams","prePeginResult","buildPrePeginPsbt","utxoSelection","fundedPrePeginTxHex","fundPeginTransaction","prePeginTxid","peginTxResult","buildPeginTxFromFundedPrePegin","SINGLE_DEPOSIT_HTLC_VOUT","peginInputPsbtResult","buildPeginInputPsbt","signedPeginInputPsbtHex","createTaprootScriptPathSignOptions","peginInputSignature","extractPeginInputSignature","depositorSignedPeginTxHex","finalizePeginInputPsbt","cleanPubkey","utxoDataPromises","utxoData","inputsWithUtxoData","psbtInputFields","signedPsbtHex","signedPsbt","e","inp","signedTxHex","unsignedPrePeginTx","depositorSignedPeginTx","vaultProvider","hashlock","onPopSigned","depositorPayoutBtcAddress","depositorLamportPkHash","preSignedBtcPopSignature","depositorEthAddress","btcPopSignature","depositorBtcPubkeyHex","ensureHexPrefix","unsignedPrePeginTxHex","payoutScriptPubKey","vaultId","publicClient","createPublicClient","http","peginFee","callData","encodeFunctionData","gasEstimate","zeroAddress","walletPubkey","isAddressFromPublicKey","bitcoin","verifyingContract","popMessage","btcPopSignatureRaw","PayoutManager","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","extractPayoutSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature"],"mappings":"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"}
|