@peachprojects/aggregator-sdk 0.1.3 → 0.1.4

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/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("ethers"),Y="https://api.peach.ag",J=50,P=10000n,N=500,ee=5e3,R=1200,V=6e4,F=[50,100,200,400,800,1200],Q="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";function T(f){return f.toLowerCase()===Q.toLowerCase()}const te=4001;var d=(f=>(f.PancakeV2="PancakeV2",f.PancakeV3="PancakeV3",f.PancakeInfinityCl="Pancake_Infinity_Cl",f.PancakeInfinityLb="Pancake_Infinity_Lb",f.UniswapV3="UniswapV3",f.UniswapV4="UniswapV4",f.Dodo="Dodo",f.ThenaV3="ThenaV3",f.ThenaFusion="Thena_Fusion",f.NomiswapStable="Nomiswap_Stable",f.Biswap="Biswap",f.Apeswap="Apeswap",f.BabyDogeSwap="BabyDogeSwap",f.BabySwap="BabySwap",f.PancakeStable="Pancake_Stable",f.ListaStable="Lista_Stable",f.SquadSwapV3="SquadSwap_V3",f.SquadSwapV2="SquadSwap_V2",f.Wombat="Wombat",f.SushiSwapV2="SushiSwap_V2",f.SushiSwapV3="SushiSwap_V3",f))(d||{});const ne={chainId:56,rpcUrl:"https://bsc-dataseed.binance.org",weth:"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",adapters:[]},re={chainId:97,rpcUrl:"https://bsc-testnet-rpc.publicnode.com",weth:"0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd",adapters:[]};class x extends Error{constructor(e){super(e),this.name="CustomFeeError"}}class U extends Error{constructor(e,t,n){super(e),this.name="ExecuteTimeoutError",this.stage=t,this.txHash=n}}const _={depth:3,splitCount:20,providers:["PANCAKEV2","PANCAKEV3","PANCAKE_INFINITY_CL","PANCAKE_INFINITY_LB","UNISWAPV3","UNISWAPV4","DODO","THENAV3","NOMISWAP_STABLE","BISWAP","APESWAP","BABYDOGESWAP","BABYSWAP","PANCAKE_STABLE","LISTA_STABLE","SQUADSWAP_V3","SQUADSWAP_V2","WOMBAT","THENA_FUSION","SUSHISWAP_V2","SUSHISWAP_V3"],clientVersion:1001500},oe=1e4;function se(f){const e={};return f.forEach((t,n)=>{e[n]=t}),e}class Z{constructor(e={}){this.baseUrl=e.baseUrl||Y,this.timeout=e.timeout||oe,this.extraHeaders=e.headers?{...e.headers}:{}}async findRoutes(e){const{from:t,target:n,amount:r,byAmountIn:o=!0,depth:s=_.depth,splitCount:a=_.splitCount,providers:i=_.providers,includeResponseHeaders:c=!1}=e,u=new URLSearchParams({from:t,target:n,amount:r.toString(),by_amount_in:o.toString(),depth:s.toString(),split_count:a.toString(),providers:i.join(","),v:_.clientVersion.toString()}),l=`${this.baseUrl}/router/find_routes?${u}`,p=new AbortController,A=setTimeout(()=>p.abort(),this.timeout);try{const m=await fetch(l,{method:"GET",headers:{Accept:"application/json",...this.extraHeaders},signal:p.signal});if(clearTimeout(A),!m.ok)throw new g(`API request failed: ${m.status} ${m.statusText}`,m.status);const S=await m.json();if(S.code!==200)throw new g(S.msg||"Route not found",S.code);if(!S.data||!S.data.paths||S.data.paths.length===0)throw new g("No routes found",404);return c?{data:S.data,responseHeaders:se(m.headers)}:S.data}catch(m){throw clearTimeout(A),m instanceof g?m:m instanceof Error?m.name==="AbortError"?new g("API request timeout",408):new g(`API request failed: ${m.message}`,0):new g("Unknown API error",0)}}async getStatus(){const e=`${this.baseUrl}/router/status`,t=new AbortController,n=setTimeout(()=>t.abort(),this.timeout);try{const r=await fetch(e,{method:"GET",headers:{Accept:"application/json",...this.extraHeaders},signal:t.signal});if(clearTimeout(n),!r.ok)throw new g(`API request failed: ${r.status} ${r.statusText}`,r.status);const o=await r.json();if(o.code!==200)throw new g(o.msg||"Failed to get status",o.code);return o.data}catch(r){throw clearTimeout(n),r instanceof g?r:r instanceof Error?r.name==="AbortError"?new g("API request timeout",408):new g(`API request failed: ${r.message}`,0):new g("Unknown API error",0)}}async getAvailableProviders(){return(await this.getStatus()).providers}setBaseUrl(e){this.baseUrl=e}getBaseUrl(){return this.baseUrl}}class g extends Error{constructor(e,t){super(e),this.name="ApiError",this.code=t}}async function L(f,e=V){if(e<=0)return f;let t;try{return await Promise.race([f,new Promise((n,r)=>{t=setTimeout(()=>{r(new U(`Wallet did not settle sendTransaction within ${e}ms.`,"wallet_send"))},e)})])}finally{t&&clearTimeout(t)}}const y=["function swap((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params) external returns (uint256 amountOut)","function swapETH((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params) external payable returns (uint256 amountOut)","function isAdapterRegistered(address adapter) external view returns (bool)","function getAdapterProtocolId(address adapter) external view returns (bytes32)","function WETH() external view returns (address)","function owner() external view returns (address)","function pendingOwner() external view returns (address)","function paused() external view returns (bool)","function maxCustomFeeBps() external view returns (uint16)","function maxProtocolCutBps() external view returns (uint16)","function protocolFeeReceiver() external view returns (address)","function protocolCutBps() external view returns (uint16)"],b=["function approve(address spender, uint256 amount) external returns (bool)","function allowance(address owner, address spender) external view returns (uint256)","function balanceOf(address account) external view returns (uint256)","function decimals() external view returns (uint8)","function symbol() external view returns (string)"],ae="0xa0FfB9c1CE1Fe56963B0321B32E7A0302114058b",ie="0xC697d2898e0D09264376196696c51D7aBbbAA4a9",ce="0x28e2ea090877bf75740558f6bfb36a5ffee9e9df",K={PANCAKEV3:d.PancakeV3,PANCAKEV2:d.PancakeV2,PANCAKE_INFINITY_CL:d.PancakeInfinityCl,PANCAKE_INFINITY_LB:d.PancakeInfinityLb,UNISWAPV3:d.UniswapV3,UNISWAPV4:d.UniswapV4,DODO:d.Dodo,THENAV3:d.ThenaV3,NOMISWAP_STABLE:d.NomiswapStable,BISWAP:d.Biswap,APESWAP:d.Apeswap,BABYDOGESWAP:d.BabyDogeSwap,BABYSWAP:d.BabySwap,PANCAKE_STABLE:d.PancakeStable,LISTA_STABLE:d.ListaStable,SQUADSWAP_V3:d.SquadSwapV3,SQUADSWAP_V2:d.SquadSwapV2,WOMBAT:d.Wombat,THENA_FUSION:d.ThenaFusion,SUSHISWAP_V2:d.SushiSwapV2,SUSHISWAP_V3:d.SushiSwapV3},O=class O{constructor(e,t,n){this.config=e,this.provider=t||new h.ethers.JsonRpcProvider(e.rpcUrl),this.routerContract=new h.ethers.Contract(e.routerAddress||h.ethers.ZeroAddress,y,this.provider),this.apiClient=new Z(n?.api)}getRouterAddress(e){const t=e.routerAddress||this.config.routerAddress;if(!t||t===h.ethers.ZeroAddress)throw new Error("No router address available. Provide routerAddress in config or use API-based getQuote.");return t}applySlippage(e,t){if(t<0||t>1e4)throw new Error("slippageBps must be between 0 and 10000");const n=e.amountOutMin*(P-BigInt(t))/P;return{...e,amountOutMin:n}}async swap(e,t,n){const r=this.getRouterAddress(e),{tx:o,method:s}=this.buildSwapTransactionRequest(e,n);let a;return e.srcNative||(a=await this.buildApprovalRequest(e.srcToken,t,e.amountIn,r,n)),{routerAddress:r,method:s,tx:o,approval:a}}async execute(e,t,n){const r=await t.getAddress(),o=await this.swap(e,r,n);try{return o.approval&&await(await this.sendTransactionWithTimeout(t,o.approval.tx,n)).wait(),await this.sendTransactionWithTimeout(t,o.tx,n)}catch(s){const a=s instanceof Error?s.message:String(s),i=/estimateGas/i.test(a),c=/missing revert data/i.test(a)||a.includes("reason=null")&&a.includes("data=null");if(i&&(c||/reason=null|data=null/.test(a))){const u="Transaction reverted during gas estimation and the RPC did not return a revert reason. Try: 1) Get a fresh quote and confirm immediately 2) Switch network or RPC 3) Increase slippage.",l=new Error(`${u} (estimateGas/missing revert data)`);throw l.cause=s,l}throw s}}encodeParams(e){return{srcToken:e.srcToken,dstToken:e.dstToken,amountIn:e.amountIn,amountOutMin:e.amountOutMin,steps:e.steps.map(t=>({adapter:t.adapter,pool:t.pool,tokenIn:t.tokenIn,tokenOut:t.tokenOut,amountIn:t.amountIn,extraData:t.extraData})),intermediateTokens:e.intermediateTokens,deadline:e.deadline,quoteId:e.quoteId,expectAmountOut:e.expectAmountOut,feeReceiver:e.feeReceiver,feeBps:e.feeBps}}getProtocolForProvider(e){if(e in K)return K[e];throw new Error(`Unsupported provider: ${e}`)}encodeSwapCalldata(e,t){const n=e.routerAddress??this.config.routerAddress??this.routerContract.target,r=this.applySlippage(e.params,t),o=e.srcNative===!0||e.dstNative===!0,s=this.encodeParams(r);if(o){const a=this.routerContract.interface.encodeFunctionData("swapETH",[s]);return{to:n,data:a,value:e.srcNative?e.amountIn:0n,method:"swapETH"}}else{const a=this.routerContract.interface.encodeFunctionData("swap",[s]);return{to:n,data:a,value:0n,method:"swap"}}}buildSwapTransactionRequest(e,t){const{to:n,data:r,value:o,method:s}=this.encodeSwapCalldata(e,t.slippageBps);return{method:s,tx:this.applyTxOverrides({to:n,data:r,value:o},t,!0)}}async buildApprovalRequest(e,t,n,r,o){const s=await this.getAllowance(e,t,r);if(!(s>=n))return{token:e,owner:t,spender:r,currentAllowance:s,requiredAmount:n,approveAmount:h.ethers.MaxUint256,tx:this.buildApprovalTransactionRequest(e,r,o)}}buildApprovalTransactionRequest(e,t,n){const o=new h.ethers.Interface(b).encodeFunctionData("approve",[t,h.ethers.MaxUint256]);return this.applyTxOverrides({to:e,data:o,value:0n},n,!1)}async getAllowance(e,t,n){return new h.ethers.Contract(e,b,this.provider).allowance(t,n)}applyTxOverrides(e,t,n){const r={...e};return t.gasPrice&&(r.gasPrice=t.gasPrice),n&&t.gasLimit&&(r.gasLimit=t.gasLimit),r}async sendTransactionWithTimeout(e,t,n){const r=n.timeoutMs??V;if(r<=0)return e.sendTransaction(t);const o=e;if(typeof o.sendUncheckedTransaction=="function"&&o.provider){const s=await L(o.sendUncheckedTransaction(t),r),a=await this.waitForTransactionResponse(o.provider,s,r,n.transactionResponsePollingIntervalsMs);if(a.response)return a.response;const i=a.rpcErrors>0?`${a.rpcErrors} transient provider error(s) and ${a.nullResponses} null response(s)`:`${a.nullResponses} null response(s)`;throw new U(`Transaction was broadcast but provider did not return TransactionResponse within ${r}ms (${i}).`,"provider_index",s)}return L(e.sendTransaction(t),r)}async waitForTransactionResponse(e,t,n,r=F){const o=Date.now()+n;let s=0,a=0,i=0;for(;Date.now()<o;){try{const u=await e.getTransaction(t);if(u)return{response:u,nullResponses:a,rpcErrors:i};a++}catch{i++}const c=this.getNextPollingDelay(r,s);s++,await this.delay(Math.min(c,Math.max(25,o-Date.now())))}return{response:null,nullResponses:a,rpcErrors:i}}async delay(e){e<=0||await new Promise(t=>{setTimeout(t,e)})}getNextPollingDelay(e,t){return e.length===0?F.at(-1)??1200:e[Math.min(t,e.length-1)]??1200}async getTokenInfo(e,t){const n=new h.ethers.Contract(e,b,this.provider),[r,o,s]=await Promise.all([n.symbol(),n.decimals(),t?n.balanceOf(t):Promise.resolve(void 0)]);return s===void 0?{symbol:r,decimals:o}:{symbol:r,decimals:o,balance:s}}async getBalance(e,t){return new h.ethers.Contract(e,b,this.provider).balanceOf(t)}async getQuote(e){const{srcToken:t,dstToken:n,amountIn:r,options:o={}}=e,{byAmountIn:s=!0,depth:a=_.depth,splitCount:i=_.splitCount,providers:c=_.providers,deadlineSeconds:u=R,includeResponseHeaders:l=!1,customFee:p}=o;O.validateCustomFee(p);const A=T(t),m=T(n),S=A?this.config.weth:t,v=m?this.config.weth:n;if(l){const{data:C,responseHeaders:k}=await this.apiClient.findRoutes({from:S,target:v,amount:r,byAmountIn:s,depth:a,splitCount:i,providers:c,includeResponseHeaders:!0});return this.buildQuoteFromApi(C,S,v,u,c,A,m,k,p)}const I=await this.apiClient.findRoutes({from:S,target:v,amount:r,byAmountIn:s,depth:a,splitCount:i,providers:c});return this.buildQuoteFromApi(I,S,v,u,c,A,m,void 0,p)}static validateCustomFee(e){if(!e)return;const{feeAccount:t,feeBps:n}=e;if(!Number.isInteger(n)||n<1||n>N)throw new x(`customFee.feeBps must be an integer in [1, ${N}] (5%), got ${n}`);if(!t||!h.ethers.isAddress(t))throw new x(`customFee.feeAccount must be a valid address, got ${t}`);if(t===h.ethers.ZeroAddress)throw new x("customFee.feeAccount must not be the zero address")}resolveRouterAddress(e){const t=e??this.config.routerAddress;if(!t||t===h.ethers.ZeroAddress)throw new Error("No router address available. Pass one explicitly or set config.routerAddress.");return t}async getProtocolFeeConfig(e){const t=this.resolveRouterAddress(e),n=new h.ethers.Contract(t,y,this.provider),[r,o]=await Promise.all([n.protocolFeeReceiver(),n.protocolCutBps()]);return{protocolFeeReceiver:r,protocolCutBps:Number(o)}}async getPlatformConfig(e){return this.getProtocolFeeConfig(e)}async getRouterConfig(e){const t=this.resolveRouterAddress(e),n=new h.ethers.Contract(t,y,this.provider),[r,o,s,a,i,c,u,l]=await Promise.all([n.WETH(),n.owner(),n.pendingOwner(),n.paused(),n.maxCustomFeeBps(),n.maxProtocolCutBps(),n.protocolFeeReceiver(),n.protocolCutBps()]);return{address:t,weth:r,owner:o,pendingOwner:s,paused:!!a,maxCustomFeeBps:Number(i),maxProtocolCutBps:Number(c),protocolFee:{protocolFeeReceiver:u,protocolCutBps:Number(l)}}}filterPathsByProviders(e,t,n,r){const o=new Set(t.map(p=>p.toUpperCase()));let s=e.filter(p=>o.has(p.provider.toUpperCase()));if(s.length===e.length)return s;const a=n.toLowerCase(),i=r.toLowerCase(),c=new Set;c.add(a);let u=!0;for(;u;){u=!1;for(const p of s)c.has(p.token_in.toLowerCase())&&!c.has(p.token_out.toLowerCase())&&(c.add(p.token_out.toLowerCase()),u=!0)}const l=new Set;for(l.add(i),u=!0;u;){u=!1;for(const p of s)l.has(p.token_out.toLowerCase())&&!l.has(p.token_in.toLowerCase())&&(l.add(p.token_in.toLowerCase()),u=!0)}return s.length,s=s.filter(p=>c.has(p.token_in.toLowerCase())&&l.has(p.token_out.toLowerCase())),s}buildQuoteFromRouteData(e,t,n,r,o){const s=this.buildQuoteFromRouteDataInternal(e,t,n,r??R,void 0);return o?.srcNative&&(s.srcNative=!0),o?.dstNative&&(s.dstNative=!0),s}buildQuoteFromApi(e,t,n,r,o,s,a,i,c){const u=this.buildQuoteFromRouteDataInternal(e,t,n,r,o,c);return s&&(u.srcNative=!0),a&&(u.dstNative=!0),i&&(u.responseHeaders=i),u}buildQuoteFromRouteDataInternal(e,t,n,r,o,s){const a=t.toLowerCase();e.paths.length;let i=e.paths.filter(w=>!(!(w.token_in.toLowerCase()===a)&&BigInt(w.amount_in)===0n&&BigInt(w.amount_out)===0n));if(i.length===0)throw new g("All route paths have zero amounts",4001);if(o&&o.length>0&&(i=this.filterPathsByProviders(i,o,t,n),i.length===0))throw new g("No valid route paths remaining after provider filtering",4001);const c=n.toLowerCase();let u=0n,l=0n;for(const w of i)w.token_in.toLowerCase()===a&&(u+=BigInt(w.amount_in)),w.token_out.toLowerCase()===c&&(l+=BigInt(w.amount_out));const p=BigInt(Math.floor(Date.now()/1e3)+r),A=new Map;for(const w of i){const E=w.token_in.toLowerCase();A.set(E,(A.get(E)??0)+1)}const m=new Map,S=i.map(w=>{const E=w.token_in.toLowerCase(),W=(m.get(E)??0)+1;m.set(E,W);const H=A.get(E),z=H>1&&W<H,X=E===a;return{adapter:w.adapter,pool:w.provider.toUpperCase()==="PANCAKE_INFINITY_CL"?ae:w.provider.toUpperCase()==="PANCAKE_INFINITY_LB"?ie:w.provider.toUpperCase()==="UNISWAPV4"?ce:w.pool,tokenIn:w.token_in,tokenOut:w.token_out,amountIn:X||z?BigInt(w.amount_in):0n,extraData:w.extra_data||"0x"}}),v=new Set;for(const w of i)w.token_out.toLowerCase()!==c&&v.add(w.token_out);const I=Array.from(v),C=s?.feeBps??0,k=s?.feeAccount??h.ethers.ZeroAddress,M=l,$=C>0?M*BigInt(C)/P:0n,B=M-$,j={srcToken:t,dstToken:n,amountIn:u,amountOutMin:B,steps:S,intermediateTokens:I,deadline:p,quoteId:e.request_id?h.ethers.id(e.request_id).slice(0,66):h.ethers.ZeroHash,expectAmountOut:B,feeReceiver:k,feeBps:C},q={routes:[{steps:i.map(w=>({pool:{address:w.pool,token0:w.token_in,token1:w.token_out,protocol:this.getProtocolForProvider(w.provider),fee:w.fee_rate?Math.round(parseFloat(w.fee_rate)*1e6):void 0},tokenIn:w.token_in,tokenOut:w.token_out,amountIn:BigInt(w.amount_in),amountOut:BigInt(w.amount_out)})),amountIn:u,amountOut:l,gasEstimate:BigInt(e.gas)}],percentages:[1e4],totalAmountIn:u,totalAmountOut:l,totalGasEstimate:BigInt(e.gas)};if(!e.contracts?.router)throw new g("API response missing contracts.router address",4002);return{srcToken:t,dstToken:n,amountIn:u,amountOut:B,priceImpact:parseFloat(e.deviation_ratio||"0"),route:q,params:j,gasEstimate:BigInt(e.gas),routerAddress:e.contracts?.router,customFee:C>0?{feeAccount:k,feeBps:C,feeAmount:$}:void 0}}async getAvailableProviders(){return this.apiClient.getAvailableProviders()}async simulate(e,t,n,r){const o=n||h.ethers.ZeroAddress,{to:s,data:a,value:i,method:c}=this.encodeSwapCalldata(e,t);if(r){const u=this.getJsonRpcProviderForStateOverrides(),l=i>0n?"0x"+i.toString(16):void 0,p=await u.send("eth_call",[{from:o,to:s,data:a,value:l},"latest",r]),[A]=this.routerContract.interface.decodeFunctionResult(c,p);return{amountOut:A,method:c}}else{const u=await this.provider.call({from:o,to:s,data:a,value:i>0n?i:void 0}),[l]=this.routerContract.interface.decodeFunctionResult(c,u);return{amountOut:l,method:c}}}getJsonRpcProviderForStateOverrides(){if(typeof this.provider.send!="function")throw new Error("stateOverrides require a JsonRpcProvider-compatible provider with send(method, params).");return this.provider}formatSimulateError(e,t,n,r){const o=e instanceof Error?e:new Error(String(e)),s=e;let a="unknown";if(s.reason&&typeof s.reason=="string")a=s.reason;else if(s.revert&&typeof s.revert=="object"){const l=s.revert;l.args&&Array.isArray(l.args)&&(a=l.args.join(", "))}else o.message&&(a=o.message);const i=t.params.steps.map((l,p)=>` Step ${p}: ${l.tokenIn.slice(0,10)}→${l.tokenOut.slice(0,10)} via adapter ${l.adapter.slice(0,10)} pool ${l.pool.slice(0,10)}`).join(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("ethers"),Z="https://api.peach.ag",te=50,k=10000n,D=500,ne=5e3,R=1200,M=6e4,F=[50,100,200,400,800,1200],j="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";function x(m){return m.toLowerCase()===j.toLowerCase()}const re=4001;var d=(m=>(m.PancakeV1="PancakeV1",m.PancakeV2="PancakeV2",m.PancakeV3="PancakeV3",m.PancakeInfinityCl="Pancake_Infinity_Cl",m.PancakeInfinityLb="Pancake_Infinity_Lb",m.UniswapV2="UniswapV2",m.UniswapV3="UniswapV3",m.UniswapV4="UniswapV4",m.Dodo="Dodo",m.ThenaV3="ThenaV3",m.ThenaFusion="Thena_Fusion",m.NomiswapStable="Nomiswap_Stable",m.Biswap="Biswap",m.Apeswap="Apeswap",m.BabyDogeSwap="BabyDogeSwap",m.BabySwap="BabySwap",m.BakerySwap="BakerySwap",m.PancakeStable="Pancake_Stable",m.ListaStable="Lista_Stable",m.SquadSwapV3="SquadSwap_V3",m.SquadSwapV2="SquadSwap_V2",m.Wombat="Wombat",m.SushiSwapV2="SushiSwap_V2",m.SushiSwapV3="SushiSwap_V3",m))(d||{});const se={chainId:56,rpcUrl:"https://bsc-dataseed.binance.org",weth:"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",adapters:[]},oe={chainId:97,rpcUrl:"https://bsc-testnet-rpc.publicnode.com",weth:"0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd",adapters:[]};class y extends Error{constructor(e){super(e),this.name="CustomFeeError"}}class $ extends Error{constructor(e,t,n){super(e),this.name="ExecuteTimeoutError",this.stage=t,this.txHash=n}}const O="0x000000000022D473030F116dDEE9F6B43aC78BA3",L=(1n<<160n)-1n,P={depth:3,splitCount:20,providers:["PANCAKEV1","PANCAKEV2","PANCAKEV3","PANCAKE_INFINITY_CL","PANCAKE_INFINITY_LB","UNISWAPV2","UNISWAPV3","UNISWAPV4","DODO","THENAV3","NOMISWAP_STABLE","BISWAP","APESWAP","BABYDOGESWAP","BABYSWAP","BAKERYSWAP","PANCAKE_STABLE","LISTA_STABLE","SQUADSWAP_V3","SQUADSWAP_V2","WOMBAT","THENA_FUSION","SUSHISWAP_V2","SUSHISWAP_V3"],clientVersion:1001500},ae=1e4;function ie(m){const e={};return m.forEach((t,n)=>{e[n]=t}),e}class X{constructor(e={}){this.baseUrl=e.baseUrl||Z,this.timeout=e.timeout||ae,this.extraHeaders=e.headers?{...e.headers}:{}}async findRoutes(e){const{from:t,target:n,amount:r,byAmountIn:o=!0,depth:s=P.depth,splitCount:a=P.splitCount,providers:i=P.providers,includeResponseHeaders:c=!1}=e,u=new URLSearchParams({from:t,target:n,amount:r.toString(),by_amount_in:o.toString(),depth:s.toString(),split_count:a.toString(),providers:i.join(","),v:P.clientVersion.toString()}),l=`${this.baseUrl}/router/find_routes?${u}`,p=new AbortController,A=setTimeout(()=>p.abort(),this.timeout);try{const w=await fetch(l,{method:"GET",headers:{Accept:"application/json",...this.extraHeaders},signal:p.signal});if(clearTimeout(A),!w.ok)throw new g(`API request failed: ${w.status} ${w.statusText}`,w.status);const S=await w.json();if(S.code!==200)throw new g(S.msg||"Route not found",S.code);if(!S.data||!S.data.paths||S.data.paths.length===0)throw new g("No routes found",404);return c?{data:S.data,responseHeaders:ie(w.headers)}:S.data}catch(w){throw clearTimeout(A),w instanceof g?w:w instanceof Error?w.name==="AbortError"?new g("API request timeout",408):new g(`API request failed: ${w.message}`,0):new g("Unknown API error",0)}}async getStatus(){const e=`${this.baseUrl}/router/status`,t=new AbortController,n=setTimeout(()=>t.abort(),this.timeout);try{const r=await fetch(e,{method:"GET",headers:{Accept:"application/json",...this.extraHeaders},signal:t.signal});if(clearTimeout(n),!r.ok)throw new g(`API request failed: ${r.status} ${r.statusText}`,r.status);const o=await r.json();if(o.code!==200)throw new g(o.msg||"Failed to get status",o.code);return o.data}catch(r){throw clearTimeout(n),r instanceof g?r:r instanceof Error?r.name==="AbortError"?new g("API request timeout",408):new g(`API request failed: ${r.message}`,0):new g("Unknown API error",0)}}async getAvailableProviders(){return(await this.getStatus()).providers}setBaseUrl(e){this.baseUrl=e}getBaseUrl(){return this.baseUrl}}class g extends Error{constructor(e,t){super(e),this.name="ApiError",this.code=t}}async function V(m,e=M){if(e<=0)return m;let t;try{return await Promise.race([m,new Promise((n,r)=>{t=setTimeout(()=>{r(new $(`Wallet did not settle sendTransaction within ${e}ms.`,"wallet_send"))},e)})])}finally{t&&clearTimeout(t)}}const N=["function swap((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params) external returns (uint256 amountOut)","function swapETH((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params) external payable returns (uint256 amountOut)","function swapWithPermit2((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params, (((address token, uint160 amount, uint48 expiration, uint48 nonce) details, address spender, uint256 sigDeadline) permitSingle, bytes signature) p2) external returns (uint256 amountOut)","function swapETHWithPermit2((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params, (((address token, uint160 amount, uint48 expiration, uint48 nonce) details, address spender, uint256 sigDeadline) permitSingle, bytes signature) p2) external returns (uint256 amountOut)","function isAdapterRegistered(address adapter) external view returns (bool)","function getAdapterProtocolId(address adapter) external view returns (bytes32)","function WETH() external view returns (address)","function owner() external view returns (address)","function pendingOwner() external view returns (address)","function paused() external view returns (bool)","function maxCustomFeeBps() external view returns (uint16)","function maxProtocolCutBps() external view returns (uint16)","function protocolFeeReceiver() external view returns (address)","function protocolCutBps() external view returns (uint16)"],T=["function approve(address spender, uint256 amount) external returns (bool)","function allowance(address owner, address spender) external view returns (uint256)","function balanceOf(address account) external view returns (uint256)","function decimals() external view returns (uint8)","function symbol() external view returns (string)"],ce=["function allowance(address user, address token, address spender) external view returns (uint160 amount, uint48 expiration, uint48 nonce)"],ue={PermitDetails:[{name:"token",type:"address"},{name:"amount",type:"uint160"},{name:"expiration",type:"uint48"},{name:"nonce",type:"uint48"}],PermitSingle:[{name:"details",type:"PermitDetails"},{name:"spender",type:"address"},{name:"sigDeadline",type:"uint256"}]},de="0xa0FfB9c1CE1Fe56963B0321B32E7A0302114058b",le="0xC697d2898e0D09264376196696c51D7aBbbAA4a9",pe="0x28e2ea090877bf75740558f6bfb36a5ffee9e9df",G={PANCAKEV3:d.PancakeV3,PANCAKEV2:d.PancakeV2,PANCAKEV1:d.PancakeV1,PANCAKE_INFINITY_CL:d.PancakeInfinityCl,PANCAKE_INFINITY_LB:d.PancakeInfinityLb,UNISWAPV2:d.UniswapV2,UNISWAPV3:d.UniswapV3,UNISWAPV4:d.UniswapV4,DODO:d.Dodo,THENAV3:d.ThenaV3,NOMISWAP_STABLE:d.NomiswapStable,BISWAP:d.Biswap,APESWAP:d.Apeswap,BABYDOGESWAP:d.BabyDogeSwap,BABYSWAP:d.BabySwap,BAKERYSWAP:d.BakerySwap,PANCAKE_STABLE:d.PancakeStable,LISTA_STABLE:d.ListaStable,SQUADSWAP_V3:d.SquadSwapV3,SQUADSWAP_V2:d.SquadSwapV2,WOMBAT:d.Wombat,THENA_FUSION:d.ThenaFusion,SUSHISWAP_V2:d.SushiSwapV2,SUSHISWAP_V3:d.SushiSwapV3},C=class C{constructor(e,t,n){this.config=e,this.provider=t||new h.ethers.JsonRpcProvider(e.rpcUrl),this.routerContract=new h.ethers.Contract(e.routerAddress||h.ethers.ZeroAddress,N,this.provider),this.apiClient=new X(n?.api)}getRouterAddress(e){const t=e.routerAddress||this.config.routerAddress;if(!t||t===h.ethers.ZeroAddress)throw new Error("No router address available. Provide routerAddress in config or use API-based getQuote.");return t}applySlippage(e,t){if(t<0||t>1e4)throw new Error("slippageBps must be between 0 and 10000");const n=e.amountOutMin*(k-BigInt(t))/k;return{...e,amountOutMin:n}}async swap(e,t,n){const r=this.getRouterAddress(e),{tx:o,method:s}=this.buildSwapTransactionRequest(e,n);let a;return e.srcNative||(a=await this.buildApprovalRequest(e.srcToken,t,e.amountIn,r,n)),{routerAddress:r,method:s,tx:o,approval:a}}async execute(e,t,n){const r=await t.getAddress(),o=await this.swap(e,r,n);try{return o.approval&&await(await this.sendTransactionWithTimeout(t,o.approval.tx,n)).wait(),await this.sendTransactionWithTimeout(t,o.tx,n)}catch(s){const a=s instanceof Error?s.message:String(s),i=/estimateGas/i.test(a),c=/missing revert data/i.test(a)||a.includes("reason=null")&&a.includes("data=null");if(i&&(c||/reason=null|data=null/.test(a))){const u="Transaction reverted during gas estimation and the RPC did not return a revert reason. Try: 1) Get a fresh quote and confirm immediately 2) Switch network or RPC 3) Increase slippage.",l=new Error(`${u} (estimateGas/missing revert data)`);throw l.cause=s,l}throw s}}encodeParams(e){return{srcToken:e.srcToken,dstToken:e.dstToken,amountIn:e.amountIn,amountOutMin:e.amountOutMin,steps:e.steps.map(t=>({adapter:t.adapter,pool:t.pool,tokenIn:t.tokenIn,tokenOut:t.tokenOut,amountIn:t.amountIn,extraData:t.extraData})),intermediateTokens:e.intermediateTokens,deadline:e.deadline,quoteId:e.quoteId,expectAmountOut:e.expectAmountOut,feeReceiver:e.feeReceiver,feeBps:e.feeBps}}getProtocolForProvider(e){if(e in G)return G[e];throw new Error(`Unsupported provider: ${e}`)}encodeSwapCalldata(e,t){const n=e.routerAddress??this.config.routerAddress??this.routerContract.target,r=this.applySlippage(e.params,t),o=e.srcNative===!0||e.dstNative===!0,s=this.encodeParams(r);if(o){const a=this.routerContract.interface.encodeFunctionData("swapETH",[s]);return{to:n,data:a,value:e.srcNative?e.amountIn:0n,method:"swapETH"}}else{const a=this.routerContract.interface.encodeFunctionData("swap",[s]);return{to:n,data:a,value:0n,method:"swap"}}}buildSwapTransactionRequest(e,t){const{to:n,data:r,value:o,method:s}=this.encodeSwapCalldata(e,t.slippageBps);return{method:s,tx:this.applyTxOverrides({to:n,data:r,value:o},t,!0)}}async buildApprovalRequest(e,t,n,r,o){const s=await this.getAllowance(e,t,r);if(!(s>=n))return{token:e,owner:t,spender:r,currentAllowance:s,requiredAmount:n,approveAmount:h.ethers.MaxUint256,tx:this.buildApprovalTransactionRequest(e,r,o)}}buildApprovalTransactionRequest(e,t,n){const o=new h.ethers.Interface(T).encodeFunctionData("approve",[t,h.ethers.MaxUint256]);return this.applyTxOverrides({to:e,data:o,value:0n},n,!1)}async getAllowance(e,t,n){return new h.ethers.Contract(e,T,this.provider).allowance(t,n)}async getPermit2Allowance(e,t,n){const r=new h.ethers.Contract(O,ce,this.provider),o=n??this.resolveRouterAddress(),[s,a,i]=await r.allowance(t,e,o);return{amount:BigInt(s),expiration:Number(a),nonce:Number(i)}}async buildPermit2TokenApproval(e,t,n,r={}){if(await this.getAllowance(e,t,O)>=n)return;const a=new h.ethers.Interface(T).encodeFunctionData("approve",[O,h.ethers.MaxUint256]),i={to:e,data:a,value:0n};return r.gasPrice&&(i.gasPrice=r.gasPrice),i}async buildPermit2TypedData(e,t,n={}){if(e.srcNative)throw new Error("Permit2 cannot be used for native-token input; use swapETH instead.");const r=this.getRouterAddress(e);this.assertUint160(e.amountIn);const{nonce:o}=await this.getPermit2Allowance(e.srcToken,t,r),s=Math.floor(Date.now()/1e3),a=n.permitAmount??L;this.assertUint160(a);const i={details:{token:e.srcToken,amount:a,expiration:n.expiration??s+720*60*60,nonce:o},spender:r,sigDeadline:n.sigDeadline??BigInt(s+1800)};return{domain:{name:"Permit2",chainId:this.config.chainId,verifyingContract:O},types:ue,values:i}}encodeSwapWithPermit2Calldata(e,t,n,r){if(e.srcNative)throw new Error("Permit2 cannot be used for native-token input; use swapETH instead.");const o=this.getRouterAddress(e),s=this.applySlippage(e.params,t),a=this.encodeParams(s),i={permitSingle:n,signature:r},c=e.dstNative?"swapETHWithPermit2":"swapWithPermit2",u=this.routerContract.interface.encodeFunctionData(c,[a,i]);return{to:o,data:u,value:0n,method:c}}async swapWithPermit2(e,t,n){if(e.srcNative)throw new Error("Permit2 cannot be used for native-token input; use swapETH instead.");const r=this.getRouterAddress(e);this.assertUint160(e.amountIn);const o=await this.buildPermit2TokenApproval(e.srcToken,t,e.amountIn,n),s=await this.getPermit2Allowance(e.srcToken,t,r),a=Math.floor(Date.now()/1e3),i=!o&&s.amount>=e.amountIn&&s.expiration>a;let c,u;i?u={details:{token:e.srcToken,amount:s.amount,expiration:s.expiration,nonce:s.nonce},spender:r,sigDeadline:0n}:(c=await this.buildPermit2TypedData(e,t,n),u=c.values);const l=e.dstNative?"swapETHWithPermit2":"swapWithPermit2";return{routerAddress:r,method:l,permit2Approval:o,typedData:c,permitSingle:u,buildSwapTx:p=>{const{to:A,data:w,value:S}=this.encodeSwapWithPermit2Calldata(e,n.slippageBps,u,p);return this.applyTxOverrides({to:A,data:w,value:S},n,!0)}}}assertUint160(e){if(e>L)throw new Error(`amount ${e} exceeds Permit2 uint160 max`)}applyTxOverrides(e,t,n){const r={...e};return t.gasPrice&&(r.gasPrice=t.gasPrice),n&&t.gasLimit&&(r.gasLimit=t.gasLimit),r}async sendTransactionWithTimeout(e,t,n){const r=n.timeoutMs??M;if(r<=0)return e.sendTransaction(t);const o=e;if(typeof o.sendUncheckedTransaction=="function"&&o.provider){const s=await V(o.sendUncheckedTransaction(t),r),a=await this.waitForTransactionResponse(o.provider,s,r,n.transactionResponsePollingIntervalsMs);if(a.response)return a.response;const i=a.rpcErrors>0?`${a.rpcErrors} transient provider error(s) and ${a.nullResponses} null response(s)`:`${a.nullResponses} null response(s)`;throw new $(`Transaction was broadcast but provider did not return TransactionResponse within ${r}ms (${i}).`,"provider_index",s)}return V(e.sendTransaction(t),r)}async waitForTransactionResponse(e,t,n,r=F){const o=Date.now()+n;let s=0,a=0,i=0;for(;Date.now()<o;){try{const u=await e.getTransaction(t);if(u)return{response:u,nullResponses:a,rpcErrors:i};a++}catch{i++}const c=this.getNextPollingDelay(r,s);s++,await this.delay(Math.min(c,Math.max(25,o-Date.now())))}return{response:null,nullResponses:a,rpcErrors:i}}async delay(e){e<=0||await new Promise(t=>{setTimeout(t,e)})}getNextPollingDelay(e,t){return e.length===0?F.at(-1)??1200:e[Math.min(t,e.length-1)]??1200}async getTokenInfo(e,t){const n=new h.ethers.Contract(e,T,this.provider),[r,o,s]=await Promise.all([n.symbol(),n.decimals(),t?n.balanceOf(t):Promise.resolve(void 0)]);return s===void 0?{symbol:r,decimals:o}:{symbol:r,decimals:o,balance:s}}async getBalance(e,t){return new h.ethers.Contract(e,T,this.provider).balanceOf(t)}async getQuote(e){const{srcToken:t,dstToken:n,amountIn:r,options:o={}}=e,{byAmountIn:s=!0,depth:a=P.depth,splitCount:i=P.splitCount,providers:c=P.providers,deadlineSeconds:u=R,includeResponseHeaders:l=!1,customFee:p}=o;C.validateCustomFee(p);const A=x(t),w=x(n),S=A?this.config.weth:t,v=w?this.config.weth:n;if(l){const{data:_,responseHeaders:b}=await this.apiClient.findRoutes({from:S,target:v,amount:r,byAmountIn:s,depth:a,splitCount:i,providers:c,includeResponseHeaders:!0});return this.buildQuoteFromApi(_,S,v,u,c,A,w,b,p)}const E=await this.apiClient.findRoutes({from:S,target:v,amount:r,byAmountIn:s,depth:a,splitCount:i,providers:c});return this.buildQuoteFromApi(E,S,v,u,c,A,w,void 0,p)}static validateCustomFee(e){if(!e)return;const{feeAccount:t,feeBps:n}=e;if(!Number.isInteger(n)||n<1||n>D)throw new y(`customFee.feeBps must be an integer in [1, ${D}] (5%), got ${n}`);if(!t||!h.ethers.isAddress(t))throw new y(`customFee.feeAccount must be a valid address, got ${t}`);if(t===h.ethers.ZeroAddress)throw new y("customFee.feeAccount must not be the zero address")}resolveRouterAddress(e){const t=e??this.config.routerAddress;if(!t||t===h.ethers.ZeroAddress)throw new Error("No router address available. Pass one explicitly or set config.routerAddress.");return t}async getProtocolFeeConfig(e){const t=this.resolveRouterAddress(e),n=new h.ethers.Contract(t,N,this.provider),[r,o]=await Promise.all([n.protocolFeeReceiver(),n.protocolCutBps()]);return{protocolFeeReceiver:r,protocolCutBps:Number(o)}}async getPlatformConfig(e){return this.getProtocolFeeConfig(e)}async getRouterConfig(e){const t=this.resolveRouterAddress(e),n=new h.ethers.Contract(t,N,this.provider),[r,o,s,a,i,c,u,l]=await Promise.all([n.WETH(),n.owner(),n.pendingOwner(),n.paused(),n.maxCustomFeeBps(),n.maxProtocolCutBps(),n.protocolFeeReceiver(),n.protocolCutBps()]);return{address:t,weth:r,owner:o,pendingOwner:s,paused:!!a,maxCustomFeeBps:Number(i),maxProtocolCutBps:Number(c),protocolFee:{protocolFeeReceiver:u,protocolCutBps:Number(l)}}}filterPathsByProviders(e,t,n,r){const o=new Set(t.map(p=>p.toUpperCase()));let s=e.filter(p=>o.has(p.provider.toUpperCase()));if(s.length===e.length)return s;const a=n.toLowerCase(),i=r.toLowerCase(),c=new Set;c.add(a);let u=!0;for(;u;){u=!1;for(const p of s)c.has(p.token_in.toLowerCase())&&!c.has(p.token_out.toLowerCase())&&(c.add(p.token_out.toLowerCase()),u=!0)}const l=new Set;for(l.add(i),u=!0;u;){u=!1;for(const p of s)l.has(p.token_out.toLowerCase())&&!l.has(p.token_in.toLowerCase())&&(l.add(p.token_in.toLowerCase()),u=!0)}return s.length,s=s.filter(p=>c.has(p.token_in.toLowerCase())&&l.has(p.token_out.toLowerCase())),s}buildQuoteFromRouteData(e,t,n,r,o){const s=this.buildQuoteFromRouteDataInternal(e,t,n,r??R,void 0);return o?.srcNative&&(s.srcNative=!0),o?.dstNative&&(s.dstNative=!0),s}buildQuoteFromApi(e,t,n,r,o,s,a,i,c){const u=this.buildQuoteFromRouteDataInternal(e,t,n,r,o,c);return s&&(u.srcNative=!0),a&&(u.dstNative=!0),i&&(u.responseHeaders=i),u}buildQuoteFromRouteDataInternal(e,t,n,r,o,s){const a=t.toLowerCase();e.paths.length;let i=e.paths.filter(f=>!(!(f.token_in.toLowerCase()===a)&&BigInt(f.amount_in)===0n&&BigInt(f.amount_out)===0n));if(i.length===0)throw new g("All route paths have zero amounts",4001);if(o&&o.length>0&&(i=this.filterPathsByProviders(i,o,t,n),i.length===0))throw new g("No valid route paths remaining after provider filtering",4001);const c=n.toLowerCase();let u=0n,l=0n;for(const f of i)f.token_in.toLowerCase()===a&&(u+=BigInt(f.amount_in)),f.token_out.toLowerCase()===c&&(l+=BigInt(f.amount_out));const p=BigInt(Math.floor(Date.now()/1e3)+r),A=new Map;for(const f of i){const I=f.token_in.toLowerCase();A.set(I,(A.get(I)??0)+1)}const w=new Map,S=i.map(f=>{const I=f.token_in.toLowerCase(),K=(w.get(I)??0)+1;w.set(I,K);const Y=A.get(I),q=Y>1&&K<Y,ee=I===a;return{adapter:f.adapter,pool:f.provider.toUpperCase()==="PANCAKE_INFINITY_CL"?de:f.provider.toUpperCase()==="PANCAKE_INFINITY_LB"?le:f.provider.toUpperCase()==="UNISWAPV4"?pe:f.pool,tokenIn:f.token_in,tokenOut:f.token_out,amountIn:ee||q?BigInt(f.amount_in):0n,extraData:f.extra_data||"0x"}}),v=new Set;for(const f of i)f.token_out.toLowerCase()!==c&&v.add(f.token_out);const E=Array.from(v),_=s?.feeBps??0,b=s?.feeAccount??h.ethers.ZeroAddress,W=l,H=_>0?W*BigInt(_)/k:0n,B=W-H,z={srcToken:t,dstToken:n,amountIn:u,amountOutMin:B,steps:S,intermediateTokens:E,deadline:p,quoteId:e.request_id?h.ethers.id(e.request_id).slice(0,66):h.ethers.ZeroHash,expectAmountOut:B,feeReceiver:b,feeBps:_},J={routes:[{steps:i.map(f=>({pool:{address:f.pool,token0:f.token_in,token1:f.token_out,protocol:this.getProtocolForProvider(f.provider),fee:f.fee_rate?Math.round(parseFloat(f.fee_rate)*1e6):void 0},tokenIn:f.token_in,tokenOut:f.token_out,amountIn:BigInt(f.amount_in),amountOut:BigInt(f.amount_out)})),amountIn:u,amountOut:l,gasEstimate:BigInt(e.gas)}],percentages:[1e4],totalAmountIn:u,totalAmountOut:l,totalGasEstimate:BigInt(e.gas)};if(!e.contracts?.router)throw new g("API response missing contracts.router address",4002);return{srcToken:t,dstToken:n,amountIn:u,amountOut:B,priceImpact:parseFloat(e.deviation_ratio||"0"),route:J,params:z,gasEstimate:BigInt(e.gas),routerAddress:e.contracts?.router,customFee:_>0?{feeAccount:b,feeBps:_,feeAmount:H}:void 0}}async getAvailableProviders(){return this.apiClient.getAvailableProviders()}async simulate(e,t,n,r){const o=n||h.ethers.ZeroAddress,{to:s,data:a,value:i,method:c}=this.encodeSwapCalldata(e,t);if(r){const u=this.getJsonRpcProviderForStateOverrides(),l=i>0n?"0x"+i.toString(16):void 0,p=await u.send("eth_call",[{from:o,to:s,data:a,value:l},"latest",r]),[A]=this.routerContract.interface.decodeFunctionResult(c,p);return{amountOut:A,method:c}}else{const u=await this.provider.call({from:o,to:s,data:a,value:i>0n?i:void 0}),[l]=this.routerContract.interface.decodeFunctionResult(c,u);return{amountOut:l,method:c}}}getJsonRpcProviderForStateOverrides(){if(typeof this.provider.send!="function")throw new Error("stateOverrides require a JsonRpcProvider-compatible provider with send(method, params).");return this.provider}formatSimulateError(e,t,n,r){const o=e instanceof Error?e:new Error(String(e)),s=e;let a="unknown";if(s.reason&&typeof s.reason=="string")a=s.reason;else if(s.revert&&typeof s.revert=="object"){const l=s.revert;l.args&&Array.isArray(l.args)&&(a=l.args.join(", "))}else o.message&&(a=o.message);const i=t.params.steps.map((l,p)=>` Step ${p}: ${l.tokenIn.slice(0,10)}→${l.tokenOut.slice(0,10)} via adapter ${l.adapter.slice(0,10)} pool ${l.pool.slice(0,10)}`).join(`
2
2
  `),c=[`Simulate ${n} failed: ${a}`,` Route: ${t.srcToken} → ${t.dstToken}`,` AmountIn: ${t.amountIn}`,` AmountOutMin: ${t.params.amountOutMin}`,` Router: ${t.routerAddress}`,` Caller: ${r}`,` Steps (${t.params.steps.length}):`,i].join(`
3
- `),u=new Error(c);return u.cause=o,u.reason=a,u}async findFailingStep(e,t,n,r,o,s=50){const a=e.params.steps;if(!a.length)return null;const i=o!=null?this.normalizeRevertReason(o):void 0;for(let c=1;c<=a.length;c++){const u=this.buildTruncatedQuote(e,c);let l,p;try{l=(await this.simulate(u,t,n,r)).amountOut}catch(v){p=v}if(p!==void 0){const v=this.normalizeRevertReason(p),I=p?.shortMessage??p?.reason??p?.message;if(i==null||v===i)return{stepIndex:c-1,step:a[c-1],error:p,revertMessage:typeof I=="string"?I:v,fullRouteRevertMessage:i};continue}if(l===void 0)continue;const A=this.getQuotedStepAmountOut(e,c-1);if(A===void 0||A===0n)continue;const m=A>l?A-l:0n;if(m===0n)continue;const S=m*P/A;if(S>BigInt(s)){const v=`Step ${c-1} deviates: quoted=${A} simulated=${l} shortfall=${m} (${S}bps, threshold=${s}bps). Likely cause: transfer-tax on ${a[c-1].tokenOut}, stale pool data, or dynamic-fee drift.`;return{stepIndex:c-1,step:a[c-1],error:new Error(v),revertMessage:v,fullRouteRevertMessage:i}}}return null}normalizeRevertReason(e){if(e==null)return;const t=e;if(typeof t.reason=="string"&&t.reason.length>0)return t.reason;const n=this.extractRevertData(e);if(n&&n.length>=10){const c=n.slice(0,10).toLowerCase();return O.KNOWN_ERROR_SELECTORS[c]??c}const r=t.shortMessage??t.message;if(typeof r!="string")return;const o=r.match(/reason="([^"]+)"/);if(o)return o[1];const s=r.match(/reverted:\s*"([^"]+)"/);if(s)return s[1];const a=r.match(/execution reverted:\s*"([^"]+)"/);if(a)return a[1];const i=r.match(/\b0x[0-9a-fA-F]{8}\b/);if(i){const c=i[0].toLowerCase();return O.KNOWN_ERROR_SELECTORS[c]??c}}extractRevertData(e){const t=new Set,n=[e];for(;n.length;){const r=n.shift();if(r==null||typeof r!="object"||t.has(r))continue;t.add(r);const o=r,s=o.data;if(typeof s=="string"&&/^0x[0-9a-fA-F]{8,}$/.test(s))return s;for(const a of["info","error","cause","revert","originalError"])o[a]&&n.push(o[a])}}getQuotedStepAmountOut(e,t){return e.route?.routes?.[0]?.steps?.[t]?.amountOut}buildTruncatedQuote(e,t){const n=e.params.steps.slice(0,t),o=n[n.length-1].tokenOut,s=o.toLowerCase(),a=e.srcToken.toLowerCase(),i=t===e.params.steps.length,c=new Set,u=[];for(const l of n){const p=l.tokenOut.toLowerCase();p===s||p===a||c.has(p)||(c.add(p),u.push(l.tokenOut))}return{...e,dstToken:o,dstNative:i?e.dstNative:!1,amountOut:i?e.amountOut:0n,customFee:i?e.customFee:void 0,params:{...e.params,dstToken:o,amountOutMin:i?e.params.amountOutMin:0n,expectAmountOut:i?e.params.expectAmountOut:0n,feeReceiver:i?e.params.feeReceiver:h.ethers.ZeroAddress,feeBps:i?e.params.feeBps:0,steps:n,intermediateTokens:u}}}buildStateOverrides(e,t,n,r,o,s){if(s?.isNative||T(e))return{};if(!n||n===h.ethers.ZeroAddress)throw new Error("buildStateOverrides requires a non-zero routerAddress.");const a=h.ethers.AbiCoder.defaultAbiCoder(),i=r||h.ethers.parseUnits("1000000",18),c=o??n,u=h.ethers.zeroPadValue(h.ethers.toBeHex(i),32),l=h.ethers.zeroPadValue(h.ethers.toBeHex(h.ethers.MaxUint256),32),p={},A=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,50,51,52,100,101,102];for(const m of A){const S=h.ethers.keccak256(a.encode(["address","uint256"],[t,m]));p[S]=u;const v=h.ethers.keccak256(a.encode(["address","uint256"],[t,m])),I=h.ethers.keccak256(a.encode(["address","bytes32"],[c,v]));p[I]=l}return{[e.toLowerCase()]:{stateDiff:p}}}};O.KNOWN_ERROR_SELECTORS={"0x2c19b8b8":"InsufficientOutput"};let D=O;const G=["function token0() external view returns (address)","function token1() external view returns (address)","function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)"],ue=["function token0() external view returns (address)","function token1() external view returns (address)","function fee() external view returns (uint24)","function liquidity() external view returns (uint128)","function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint32 feeProtocol, bool unlocked)"],de="0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73",le=["function getPair(address tokenA, address tokenB) external view returns (address pair)"],pe="0x86407bEa2078ea5f5EB5A52B2caA963bC1F889Da",he=["function getPair(address tokenA, address tokenB) external view returns (address pair)"],fe="0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865",we=["function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool)"],me=[100,500,2500,1e4],Ae=60000n,Se=120000n,ve=100000n;class ge{constructor(e,t){this.poolCache=new Map,this.provider=e,this.v2Factory=new h.ethers.Contract(de,le,e),this.v3Factory=new h.ethers.Contract(fe,we,e),this.babySwapFactory=new h.ethers.Contract(pe,he,e)}async findBestRoute(e,t,n){const r=await this.discoverPools(e,t);if(r.length===0)throw new Error(`No pools found for ${e} -> ${t}`);const s=(await this.calculateRoutes(r,e,t,n)).reduce((a,i)=>i.amountOut>a.amountOut?i:a);return{routes:[s],percentages:[1e4],totalAmountIn:n,totalAmountOut:s.amountOut,totalGasEstimate:s.gasEstimate}}async discoverPools(e,t){const n=[];try{const r=await this.findV2Pool(e,t);r&&n.push(r)}catch{}for(const r of me)try{const o=await this.findV3Pool(e,t,r);o&&n.push(o)}catch{}try{const r=await this.findBabySwapPool(e,t);r&&n.push(r)}catch{}return n}async findV2Pool(e,t){const n=`v2-${e}-${t}`;if(this.poolCache.has(n))return this.poolCache.get(n);const r=await this.v2Factory.getPair(e,t);if(r===h.ethers.ZeroAddress)return null;const o=new h.ethers.Contract(r,G,this.provider),[s,a,i]=await Promise.all([o.token0(),o.token1(),o.getReserves()]),c={address:r,token0:s,token1:a,protocol:d.PancakeV2,reserve0:i.reserve0,reserve1:i.reserve1};return this.poolCache.set(n,c),c}async findV3Pool(e,t,n){const r=`v3-${e}-${t}-${n}`;if(this.poolCache.has(r))return this.poolCache.get(r);const o=await this.v3Factory.getPool(e,t,n);if(o===h.ethers.ZeroAddress)return null;const s=new h.ethers.Contract(o,ue,this.provider),[a,i,c]=await Promise.all([s.token0(),s.token1(),s.liquidity()]);if(c===0n)return null;const u={address:o,token0:a,token1:i,protocol:d.PancakeV3,fee:n,liquidity:c};return this.poolCache.set(r,u),u}async findBabySwapPool(e,t){const n=`babyswap-${e}-${t}`;if(this.poolCache.has(n))return this.poolCache.get(n);const r=await this.babySwapFactory.getPair(e,t);if(r===h.ethers.ZeroAddress)return null;const o=new h.ethers.Contract(r,G,this.provider),[s,a,i]=await Promise.all([o.token0(),o.token1(),o.getReserves()]),c={address:r,token0:s,token1:a,protocol:d.BabySwap,reserve0:i.reserve0,reserve1:i.reserve1};return this.poolCache.set(n,c),c}async calculateRoutes(e,t,n,r){const o=[];for(const s of e)try{const a=await this.getAmountOut(s,t,n,r);a>0n&&o.push({steps:[{pool:s,tokenIn:t,tokenOut:n,amountIn:r,amountOut:a}],amountIn:r,amountOut:a,gasEstimate:s.protocol===d.PancakeV2||s.protocol===d.BabySwap?Ae:s.protocol===d.Dodo?ve:Se})}catch{}return o}async getAmountOut(e,t,n,r){if(e.protocol===d.PancakeV2)return this.getV2AmountOut(e,t,r);if(e.protocol===d.BabySwap)return this.getBabySwapAmountOut(e,t,r);if(e.protocol===d.Dodo)throw new Error("DODO amount out not supported in local route discovery");return this.estimateV3AmountOut(e,t,r)}getV2AmountOut(e,t,n){const r=t.toLowerCase()===e.token0.toLowerCase(),[o,s]=r?[e.reserve0,e.reserve1]:[e.reserve1,e.reserve0],a=n*9975n,i=a*s,c=o*10000n+a;return i/c}getBabySwapAmountOut(e,t,n){const r=t.toLowerCase()===e.token0.toLowerCase(),[o,s]=r?[e.reserve0,e.reserve1]:[e.reserve1,e.reserve0],a=n*998n,i=a*s,c=o*1000n+a;return i/c}estimateV3AmountOut(e,t,n){const o=1000000n-BigInt(e.fee||2500);return n*o/1000000n}clearCache(){this.poolCache.clear()}}class Ee{constructor(e){this.adapters=e}build(e,t,n,r,o=R){const s=this.flattenRoutes(e),a=this.mergeIdenticalPools(s),i=this.topologicalSort(a,t),c=this.convertToSwapSteps(i),u=this.extractIntermediates(i,t,n),l=BigInt(Math.floor(Date.now()/1e3)+o);return{srcToken:t,dstToken:n,amountIn:e.totalAmountIn,amountOutMin:r,steps:c,intermediateTokens:u,deadline:l,quoteId:h.ethers.ZeroHash,expectAmountOut:e.totalAmountOut,feeReceiver:h.ethers.ZeroAddress,feeBps:0}}flattenRoutes(e){const t=[];for(let n=0;n<e.routes.length;n++){const r=e.routes[n],o=e.percentages[n],s=e.totalAmountIn*BigInt(o)/P;for(let a=0;a<r.steps.length;a++){const i=r.steps[a];t.push({pool:i.pool,tokenIn:i.tokenIn,tokenOut:i.tokenOut,amountIn:a===0?s:0n,routeIndex:n,stepIndex:a})}}return t}mergeIdenticalPools(e){const t=new Map,n=[];for(const r of e){const o=`${r.pool.address}-${r.tokenIn}-${r.tokenOut}`;if(t.has(o)){const s=t.get(o);r.amountIn>0n&&s.amountIn>0n&&(s.amountIn=0n)}else{const s={...r};t.set(o,s),n.push(s)}}for(const r of n){const o=`${r.pool.address}-${r.tokenIn}-${r.tokenOut}`;e.filter(a=>`${a.pool.address}-${a.tokenIn}-${a.tokenOut}`===o).length>1&&(r.amountIn=0n)}return n}topologicalSort(e,t){const n=new Map,r=new Map,o=new Map;for(const i of e){const c=this.stepKey(i);r.set(c,i),n.set(c,0),o.set(c,[])}for(const i of e){const c=this.stepKey(i);if(i.tokenIn!==t){for(const u of e)if(u.tokenOut===i.tokenIn){const l=this.stepKey(u);l!==c&&(o.get(l).push(c),n.set(c,(n.get(c)||0)+1))}}}const s=[];for(const[i,c]of n)c===0&&s.push(i);const a=[];for(;s.length>0;){const i=s.shift(),c=r.get(i);a.push(c);for(const u of o.get(i)||[]){const l=(n.get(u)||0)-1;n.set(u,l),l===0&&s.push(u)}}if(a.length!==e.length)throw new Error("Circular dependency detected in route");return a}convertToSwapSteps(e){return e.map(t=>{const n=this.adapters.get(t.pool.protocol);if(!n)throw new Error(`No adapter for protocol: ${t.pool.protocol}`);return{adapter:n,pool:t.pool.address,tokenIn:t.tokenIn,tokenOut:t.tokenOut,amountIn:t.amountIn,extraData:this.encodeExtraData(t.pool)}})}encodeExtraData(e){switch(e.protocol){case d.PancakeV2:return"0x";case d.PancakeV3:case d.UniswapV3:case d.UniswapV4:case d.SquadSwapV3:case d.ThenaFusion:return"0x";case d.PancakeInfinityCl:case d.PancakeInfinityLb:return"0x";case d.Dodo:return"0x";case d.NomiswapStable:return"0x";case d.Biswap:return"0x";case d.Apeswap:return"0x";case d.BabyDogeSwap:return"0x";case d.BabySwap:return"0x";case d.SquadSwapV2:return"0x";case d.SushiSwapV2:return"0x";case d.SushiSwapV3:return"0x";case d.PancakeStable:return"0x";case d.ListaStable:return"0x";case d.Wombat:return"0x";default:return"0x"}}extractIntermediates(e,t,n){const r=new Set;for(const o of e)o.tokenOut!==n&&r.add(o.tokenOut);return r.delete(t),r.delete(n),Array.from(r)}stepKey(e){return`${e.pool.address}-${e.tokenIn}-${e.tokenOut}`}}exports.API_DEFAULTS=_;exports.ApiClient=Z;exports.ApiError=g;exports.BPS_DENOMINATOR=P;exports.BSC_MAINNET_CONFIG=ne;exports.BSC_TESTNET_CONFIG=re;exports.CustomFeeError=x;exports.DEFAULT_API_URL=Y;exports.DEFAULT_DEADLINE_SECONDS=R;exports.DEFAULT_EXECUTE_TIMEOUT_MS=V;exports.DEFAULT_SLIPPAGE_BPS=J;exports.DEFAULT_TRANSACTION_RESPONSE_POLL_INTERVALS_MS=F;exports.ERR_ZERO_AMOUNT_PATHS=te;exports.ExecuteTimeoutError=U;exports.MAX_FEE_BPS=N;exports.MAX_PLATFORM_CUT_BPS=ee;exports.NATIVE_TOKEN_ADDRESS=Q;exports.PeachClient=D;exports.ProtocolType=d;exports.RouteDiscovery=ge;exports.SwapBuilder=Ee;exports.isNativeTokenAddress=T;exports.withWalletSendTimeout=L;
3
+ `),u=new Error(c);return u.cause=o,u.reason=a,u}async findFailingStep(e,t,n,r,o,s=50){const a=e.params.steps;if(!a.length)return null;const i=o!=null?this.normalizeRevertReason(o):void 0;for(let c=1;c<=a.length;c++){const u=this.buildTruncatedQuote(e,c);let l,p;try{l=(await this.simulate(u,t,n,r)).amountOut}catch(v){p=v}if(p!==void 0){const v=this.normalizeRevertReason(p),E=p?.shortMessage??p?.reason??p?.message;if(i==null||v===i)return{stepIndex:c-1,step:a[c-1],error:p,revertMessage:typeof E=="string"?E:v,fullRouteRevertMessage:i};continue}if(l===void 0)continue;const A=this.getQuotedStepAmountOut(e,c-1);if(A===void 0||A===0n)continue;const w=A>l?A-l:0n;if(w===0n)continue;const S=w*k/A;if(S>BigInt(s)){const v=`Step ${c-1} deviates: quoted=${A} simulated=${l} shortfall=${w} (${S}bps, threshold=${s}bps). Likely cause: transfer-tax on ${a[c-1].tokenOut}, stale pool data, or dynamic-fee drift.`;return{stepIndex:c-1,step:a[c-1],error:new Error(v),revertMessage:v,fullRouteRevertMessage:i}}}return null}normalizeRevertReason(e){if(e==null)return;const t=e;if(typeof t.reason=="string"&&t.reason.length>0)return t.reason;const n=this.extractRevertData(e);if(n&&n.length>=10){const c=n.slice(0,10).toLowerCase();return C.KNOWN_ERROR_SELECTORS[c]??c}const r=t.shortMessage??t.message;if(typeof r!="string")return;const o=r.match(/reason="([^"]+)"/);if(o)return o[1];const s=r.match(/reverted:\s*"([^"]+)"/);if(s)return s[1];const a=r.match(/execution reverted:\s*"([^"]+)"/);if(a)return a[1];const i=r.match(/\b0x[0-9a-fA-F]{8}\b/);if(i){const c=i[0].toLowerCase();return C.KNOWN_ERROR_SELECTORS[c]??c}}extractRevertData(e){const t=new Set,n=[e];for(;n.length;){const r=n.shift();if(r==null||typeof r!="object"||t.has(r))continue;t.add(r);const o=r,s=o.data;if(typeof s=="string"&&/^0x[0-9a-fA-F]{8,}$/.test(s))return s;for(const a of["info","error","cause","revert","originalError"])o[a]&&n.push(o[a])}}getQuotedStepAmountOut(e,t){return e.route?.routes?.[0]?.steps?.[t]?.amountOut}buildTruncatedQuote(e,t){const n=e.params.steps.slice(0,t),o=n[n.length-1].tokenOut,s=o.toLowerCase(),a=e.srcToken.toLowerCase(),i=t===e.params.steps.length,c=new Set,u=[];for(const l of n){const p=l.tokenOut.toLowerCase();p===s||p===a||c.has(p)||(c.add(p),u.push(l.tokenOut))}return{...e,dstToken:o,dstNative:i?e.dstNative:!1,amountOut:i?e.amountOut:0n,customFee:i?e.customFee:void 0,params:{...e.params,dstToken:o,amountOutMin:i?e.params.amountOutMin:0n,expectAmountOut:i?e.params.expectAmountOut:0n,feeReceiver:i?e.params.feeReceiver:h.ethers.ZeroAddress,feeBps:i?e.params.feeBps:0,steps:n,intermediateTokens:u}}}buildStateOverrides(e,t,n,r,o,s){if(s?.isNative||x(e))return{};if(!n||n===h.ethers.ZeroAddress)throw new Error("buildStateOverrides requires a non-zero routerAddress.");const a=h.ethers.AbiCoder.defaultAbiCoder(),i=r||h.ethers.parseUnits("1000000",18),c=o??n,u=h.ethers.zeroPadValue(h.ethers.toBeHex(i),32),l=h.ethers.zeroPadValue(h.ethers.toBeHex(h.ethers.MaxUint256),32),p={},A=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,50,51,52,100,101,102];for(const w of A){const S=h.ethers.keccak256(a.encode(["address","uint256"],[t,w]));p[S]=u;const v=h.ethers.keccak256(a.encode(["address","uint256"],[t,w])),E=h.ethers.keccak256(a.encode(["address","bytes32"],[c,v]));p[E]=l}return{[e.toLowerCase()]:{stateDiff:p}}}};C.KNOWN_ERROR_SELECTORS={"0x2c19b8b8":"InsufficientOutput"};let U=C;const Q=["function token0() external view returns (address)","function token1() external view returns (address)","function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)"],he=["function token0() external view returns (address)","function token1() external view returns (address)","function fee() external view returns (uint24)","function liquidity() external view returns (uint128)","function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint32 feeProtocol, bool unlocked)"],me="0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73",fe=["function getPair(address tokenA, address tokenB) external view returns (address pair)"],we="0x86407bEa2078ea5f5EB5A52B2caA963bC1F889Da",Ae=["function getPair(address tokenA, address tokenB) external view returns (address pair)"],Se="0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865",ve=["function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool)"],ge=[100,500,2500,1e4],Ie=60000n,Ee=120000n,Pe=100000n;class _e{constructor(e,t){this.poolCache=new Map,this.provider=e,this.v2Factory=new h.ethers.Contract(me,fe,e),this.v3Factory=new h.ethers.Contract(Se,ve,e),this.babySwapFactory=new h.ethers.Contract(we,Ae,e)}async findBestRoute(e,t,n){const r=await this.discoverPools(e,t);if(r.length===0)throw new Error(`No pools found for ${e} -> ${t}`);const s=(await this.calculateRoutes(r,e,t,n)).reduce((a,i)=>i.amountOut>a.amountOut?i:a);return{routes:[s],percentages:[1e4],totalAmountIn:n,totalAmountOut:s.amountOut,totalGasEstimate:s.gasEstimate}}async discoverPools(e,t){const n=[];try{const r=await this.findV2Pool(e,t);r&&n.push(r)}catch{}for(const r of ge)try{const o=await this.findV3Pool(e,t,r);o&&n.push(o)}catch{}try{const r=await this.findBabySwapPool(e,t);r&&n.push(r)}catch{}return n}async findV2Pool(e,t){const n=`v2-${e}-${t}`;if(this.poolCache.has(n))return this.poolCache.get(n);const r=await this.v2Factory.getPair(e,t);if(r===h.ethers.ZeroAddress)return null;const o=new h.ethers.Contract(r,Q,this.provider),[s,a,i]=await Promise.all([o.token0(),o.token1(),o.getReserves()]),c={address:r,token0:s,token1:a,protocol:d.PancakeV2,reserve0:i.reserve0,reserve1:i.reserve1};return this.poolCache.set(n,c),c}async findV3Pool(e,t,n){const r=`v3-${e}-${t}-${n}`;if(this.poolCache.has(r))return this.poolCache.get(r);const o=await this.v3Factory.getPool(e,t,n);if(o===h.ethers.ZeroAddress)return null;const s=new h.ethers.Contract(o,he,this.provider),[a,i,c]=await Promise.all([s.token0(),s.token1(),s.liquidity()]);if(c===0n)return null;const u={address:o,token0:a,token1:i,protocol:d.PancakeV3,fee:n,liquidity:c};return this.poolCache.set(r,u),u}async findBabySwapPool(e,t){const n=`babyswap-${e}-${t}`;if(this.poolCache.has(n))return this.poolCache.get(n);const r=await this.babySwapFactory.getPair(e,t);if(r===h.ethers.ZeroAddress)return null;const o=new h.ethers.Contract(r,Q,this.provider),[s,a,i]=await Promise.all([o.token0(),o.token1(),o.getReserves()]),c={address:r,token0:s,token1:a,protocol:d.BabySwap,reserve0:i.reserve0,reserve1:i.reserve1};return this.poolCache.set(n,c),c}async calculateRoutes(e,t,n,r){const o=[];for(const s of e)try{const a=await this.getAmountOut(s,t,n,r);a>0n&&o.push({steps:[{pool:s,tokenIn:t,tokenOut:n,amountIn:r,amountOut:a}],amountIn:r,amountOut:a,gasEstimate:s.protocol===d.PancakeV2||s.protocol===d.BabySwap?Ie:s.protocol===d.Dodo?Pe:Ee})}catch{}return o}async getAmountOut(e,t,n,r){if(e.protocol===d.PancakeV2)return this.getV2AmountOut(e,t,r);if(e.protocol===d.BabySwap)return this.getBabySwapAmountOut(e,t,r);if(e.protocol===d.Dodo)throw new Error("DODO amount out not supported in local route discovery");return this.estimateV3AmountOut(e,t,r)}getV2AmountOut(e,t,n){const r=t.toLowerCase()===e.token0.toLowerCase(),[o,s]=r?[e.reserve0,e.reserve1]:[e.reserve1,e.reserve0],a=n*9975n,i=a*s,c=o*10000n+a;return i/c}getBabySwapAmountOut(e,t,n){const r=t.toLowerCase()===e.token0.toLowerCase(),[o,s]=r?[e.reserve0,e.reserve1]:[e.reserve1,e.reserve0],a=n*998n,i=a*s,c=o*1000n+a;return i/c}estimateV3AmountOut(e,t,n){const o=1000000n-BigInt(e.fee||2500);return n*o/1000000n}clearCache(){this.poolCache.clear()}}class ke{constructor(e){this.adapters=e}build(e,t,n,r,o=R){const s=this.flattenRoutes(e),a=this.mergeIdenticalPools(s),i=this.topologicalSort(a,t),c=this.convertToSwapSteps(i),u=this.extractIntermediates(i,t,n),l=BigInt(Math.floor(Date.now()/1e3)+o);return{srcToken:t,dstToken:n,amountIn:e.totalAmountIn,amountOutMin:r,steps:c,intermediateTokens:u,deadline:l,quoteId:h.ethers.ZeroHash,expectAmountOut:e.totalAmountOut,feeReceiver:h.ethers.ZeroAddress,feeBps:0}}flattenRoutes(e){const t=[];for(let n=0;n<e.routes.length;n++){const r=e.routes[n],o=e.percentages[n],s=e.totalAmountIn*BigInt(o)/k;for(let a=0;a<r.steps.length;a++){const i=r.steps[a];t.push({pool:i.pool,tokenIn:i.tokenIn,tokenOut:i.tokenOut,amountIn:a===0?s:0n,routeIndex:n,stepIndex:a})}}return t}mergeIdenticalPools(e){const t=new Map,n=[];for(const r of e){const o=`${r.pool.address}-${r.tokenIn}-${r.tokenOut}`;if(t.has(o)){const s=t.get(o);r.amountIn>0n&&s.amountIn>0n&&(s.amountIn=0n)}else{const s={...r};t.set(o,s),n.push(s)}}for(const r of n){const o=`${r.pool.address}-${r.tokenIn}-${r.tokenOut}`;e.filter(a=>`${a.pool.address}-${a.tokenIn}-${a.tokenOut}`===o).length>1&&(r.amountIn=0n)}return n}topologicalSort(e,t){const n=new Map,r=new Map,o=new Map;for(const i of e){const c=this.stepKey(i);r.set(c,i),n.set(c,0),o.set(c,[])}for(const i of e){const c=this.stepKey(i);if(i.tokenIn!==t){for(const u of e)if(u.tokenOut===i.tokenIn){const l=this.stepKey(u);l!==c&&(o.get(l).push(c),n.set(c,(n.get(c)||0)+1))}}}const s=[];for(const[i,c]of n)c===0&&s.push(i);const a=[];for(;s.length>0;){const i=s.shift(),c=r.get(i);a.push(c);for(const u of o.get(i)||[]){const l=(n.get(u)||0)-1;n.set(u,l),l===0&&s.push(u)}}if(a.length!==e.length)throw new Error("Circular dependency detected in route");return a}convertToSwapSteps(e){return e.map(t=>{const n=this.adapters.get(t.pool.protocol);if(!n)throw new Error(`No adapter for protocol: ${t.pool.protocol}`);return{adapter:n,pool:t.pool.address,tokenIn:t.tokenIn,tokenOut:t.tokenOut,amountIn:t.amountIn,extraData:this.encodeExtraData(t.pool)}})}encodeExtraData(e){switch(e.protocol){case d.PancakeV1:return"0x";case d.PancakeV2:return"0x";case d.UniswapV2:return"0x";case d.PancakeV3:case d.UniswapV3:case d.UniswapV4:case d.SquadSwapV3:case d.ThenaFusion:return"0x";case d.PancakeInfinityCl:case d.PancakeInfinityLb:return"0x";case d.Dodo:return"0x";case d.NomiswapStable:return"0x";case d.Biswap:return"0x";case d.Apeswap:return"0x";case d.BabyDogeSwap:return"0x";case d.BabySwap:return"0x";case d.BakerySwap:return"0x";case d.SquadSwapV2:return"0x";case d.SushiSwapV2:return"0x";case d.SushiSwapV3:return"0x";case d.PancakeStable:return"0x";case d.ListaStable:return"0x";case d.Wombat:return"0x";default:return"0x"}}extractIntermediates(e,t,n){const r=new Set;for(const o of e)o.tokenOut!==n&&r.add(o.tokenOut);return r.delete(t),r.delete(n),Array.from(r)}stepKey(e){return`${e.pool.address}-${e.tokenIn}-${e.tokenOut}`}}exports.API_DEFAULTS=P;exports.ApiClient=X;exports.ApiError=g;exports.BPS_DENOMINATOR=k;exports.BSC_MAINNET_CONFIG=se;exports.BSC_TESTNET_CONFIG=oe;exports.CustomFeeError=y;exports.DEFAULT_API_URL=Z;exports.DEFAULT_DEADLINE_SECONDS=R;exports.DEFAULT_EXECUTE_TIMEOUT_MS=M;exports.DEFAULT_SLIPPAGE_BPS=te;exports.DEFAULT_TRANSACTION_RESPONSE_POLL_INTERVALS_MS=F;exports.ERR_ZERO_AMOUNT_PATHS=re;exports.ExecuteTimeoutError=$;exports.MAX_FEE_BPS=D;exports.MAX_PLATFORM_CUT_BPS=ne;exports.NATIVE_TOKEN_ADDRESS=j;exports.PERMIT2_ADDRESS=O;exports.PERMIT2_MAX_AMOUNT=L;exports.PeachClient=U;exports.ProtocolType=d;exports.RouteDiscovery=_e;exports.SwapBuilder=ke;exports.isNativeTokenAddress=x;exports.withWalletSendTimeout=V;
4
4
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.ts CHANGED
@@ -318,7 +318,7 @@ export declare function isNativeTokenAddress(address: string): boolean;
318
318
  /**
319
319
  * Known DEX providers supported by the SDK.
320
320
  */
321
- export declare type KnownProvider = "PANCAKEV2" | "PANCAKEV3" | "PANCAKE_INFINITY_CL" | "PANCAKE_INFINITY_LB" | "UNISWAPV3" | "UNISWAPV4" | "DODO" | "THENAV3" | "THENA_FUSION" | "NOMISWAP_STABLE" | "BISWAP" | "APESWAP" | "BABYDOGESWAP" | "BABYSWAP" | "PANCAKE_STABLE" | "LISTA_STABLE" | "SQUADSWAP_V3" | "SQUADSWAP_V2" | "WOMBAT" | "SUSHISWAP_V2" | "SUSHISWAP_V3";
321
+ export declare type KnownProvider = "PANCAKEV1" | "PANCAKEV2" | "PANCAKEV3" | "PANCAKE_INFINITY_CL" | "PANCAKE_INFINITY_LB" | "UNISWAPV2" | "UNISWAPV3" | "UNISWAPV4" | "DODO" | "THENAV3" | "THENA_FUSION" | "NOMISWAP_STABLE" | "BISWAP" | "APESWAP" | "BABYDOGESWAP" | "BABYSWAP" | "BAKERYSWAP" | "PANCAKE_STABLE" | "LISTA_STABLE" | "SQUADSWAP_V3" | "SQUADSWAP_V2" | "WOMBAT" | "SUSHISWAP_V2" | "SUSHISWAP_V3";
322
322
 
323
323
  /**
324
324
  * Client-side default cap on the integrator-set custom fee. Mirrors the PeachRouter v2
@@ -394,6 +394,60 @@ export declare class PeachClient {
394
394
  private buildApprovalRequest;
395
395
  private buildApprovalTransactionRequest;
396
396
  private getAllowance;
397
+ /**
398
+ * Read the current Permit2 AllowanceTransfer state for (owner, token, spender).
399
+ * `spender` defaults to the router address. The returned `nonce` feeds the next PermitSingle;
400
+ * `amount` / `expiration` decide whether a fresh signature is needed.
401
+ */
402
+ getPermit2Allowance(token: string, owner: string, spender?: string): Promise<{
403
+ amount: bigint;
404
+ expiration: number;
405
+ nonce: number;
406
+ }>;
407
+ /**
408
+ * Build the ONE-TIME `token.approve(PERMIT2, max)` tx, or undefined when the token's existing
409
+ * Permit2 allowance already covers `amount`. This is the only on-chain approval Permit2 needs;
410
+ * once set, every future swap of this token is signature-only.
411
+ */
412
+ buildPermit2TokenApproval(token: string, owner: string, amount: bigint, options?: {
413
+ gasPrice?: bigint;
414
+ }): Promise<SwapTxRequest | undefined>;
415
+ /**
416
+ * Build the EIP-712 PermitSingle the user signs to grant the router a Permit2 allowance.
417
+ * Reads the current sequential nonce from Permit2; `permitSingle.spender` is the router.
418
+ * Pass the result straight into `signer.signTypedData(domain, types, values)`.
419
+ */
420
+ buildPermit2TypedData(quote: Quote, owner: string, options?: {
421
+ permitAmount?: bigint;
422
+ expiration?: number;
423
+ sigDeadline?: bigint;
424
+ }): Promise<Permit2TypedData>;
425
+ /**
426
+ * Encode calldata for swapWithPermit2 / swapETHWithPermit2. Routes to swapETHWithPermit2
427
+ * when the quote's dstToken is native. Pass `"0x"` as `signature` to reuse an existing
428
+ * on-chain Permit2 allowance (the router then skips the permit() call).
429
+ */
430
+ encodeSwapWithPermit2Calldata(quote: Quote, slippageBps: number, permitSingle: Permit2PermitSingle, signature: string): {
431
+ to: string;
432
+ data: string;
433
+ value: bigint;
434
+ method: "swapWithPermit2" | "swapETHWithPermit2";
435
+ };
436
+ /**
437
+ * Prepare a single-transaction Permit2 swap. Returns the optional one-time token->Permit2
438
+ * approval, the EIP-712 payload to sign (or undefined when an existing allowance can be
439
+ * reused), and a `buildSwapTx(signature)` closure for the final swap tx.
440
+ *
441
+ * Integrator flow:
442
+ * const req = await client.swapWithPermit2(quote, owner, { slippageBps: 50 });
443
+ * if (req.permit2Approval) await signer.sendTransaction(req.permit2Approval); // once per token
444
+ * const sig = req.typedData
445
+ * ? await signer.signTypedData(req.typedData.domain, req.typedData.types, req.typedData.values)
446
+ * : "0x";
447
+ * await signer.sendTransaction(req.buildSwapTx(sig));
448
+ */
449
+ swapWithPermit2(quote: Quote, owner: string, options: Permit2Options): Promise<Permit2SwapRequest>;
450
+ private assertUint160;
397
451
  private applyTxOverrides;
398
452
  private sendTransactionWithTimeout;
399
453
  private waitForTransactionResponse;
@@ -598,6 +652,88 @@ export declare interface PeachConfig {
598
652
  adapters: AdapterConfig[];
599
653
  }
600
654
 
655
+ /** Canonical Uniswap Permit2 singleton. Same address on every EVM chain (incl. BSC). */
656
+ export declare const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
657
+
658
+ /** Max value of a Permit2 amount (uint160). */
659
+ export declare const PERMIT2_MAX_AMOUNT: bigint;
660
+
661
+ export declare interface Permit2Options {
662
+ /** Slippage tolerance in basis points (e.g. 50 = 0.5%). Required. */
663
+ slippageBps: number;
664
+ /** Gas price in wei. Applied to the swap tx. */
665
+ gasPrice?: bigint;
666
+ /** Gas limit for the swap tx. */
667
+ gasLimit?: bigint;
668
+ /** Permit2 allowance amount to request (default: MaxUint160 so repeat swaps need no new sign). */
669
+ permitAmount?: bigint;
670
+ /** Permit2 allowance expiration, unix-seconds (default: now + 30 days). */
671
+ expiration?: number;
672
+ /** EIP-712 signature deadline, unix-seconds (default: now + 30 min). */
673
+ sigDeadline?: bigint;
674
+ }
675
+
676
+ export declare interface Permit2PermitDetails {
677
+ token: string;
678
+ /** uint160 */
679
+ amount: bigint;
680
+ /** uint48 unix-seconds expiration of the allowance. */
681
+ expiration: number;
682
+ /** uint48 sequential nonce per (owner, token, spender). */
683
+ nonce: number;
684
+ }
685
+
686
+ export declare interface Permit2PermitSingle {
687
+ details: Permit2PermitDetails;
688
+ /** Spender — the PeachRouter address. */
689
+ spender: string;
690
+ /** uint256 deadline on the EIP-712 signature itself. */
691
+ sigDeadline: bigint;
692
+ }
693
+
694
+ /** Matches the on-chain `IPeachRouter.Permit2Sig` tuple. */
695
+ export declare interface Permit2Sig {
696
+ permitSingle: Permit2PermitSingle;
697
+ /** `"0x"` (empty) reuses an existing on-chain Permit2 allowance (skips the permit() call). */
698
+ signature: string;
699
+ }
700
+
701
+ export declare interface Permit2SwapRequest {
702
+ routerAddress: string;
703
+ method: "swapWithPermit2" | "swapETHWithPermit2";
704
+ /**
705
+ * One-time `token.approve(PERMIT2, max)` tx — present ONLY when the token's existing
706
+ * Permit2 allowance is insufficient. Send it once per token; afterwards it stays undefined.
707
+ */
708
+ permit2Approval?: SwapTxRequest;
709
+ /**
710
+ * EIP-712 payload to sign with `signer.signTypedData(domain, types, values)`. Undefined when
711
+ * an existing on-chain Permit2 allowance is still valid (zero-signature repeat swap).
712
+ */
713
+ typedData?: Permit2TypedData;
714
+ /** The PermitSingle the `typedData` was built from (current nonce snapshot). */
715
+ permitSingle: Permit2PermitSingle;
716
+ /**
717
+ * Build the final swap tx from the user's EIP-712 signature. Pass `"0x"` to reuse an
718
+ * existing valid allowance (only when `typedData` is undefined).
719
+ */
720
+ buildSwapTx: (signature: string) => SwapTxRequest;
721
+ }
722
+
723
+ /** EIP-712 payload for `signer.signTypedData(domain, types, values)`. */
724
+ export declare interface Permit2TypedData {
725
+ domain: {
726
+ name: string;
727
+ chainId: number;
728
+ verifyingContract: string;
729
+ };
730
+ types: Record<string, {
731
+ name: string;
732
+ type: string;
733
+ }[]>;
734
+ values: Permit2PermitSingle;
735
+ }
736
+
601
737
  /** @deprecated Use {@link ProtocolFeeConfig}. Kept as an alias for the pre-v2 name. */
602
738
  export declare type PlatformConfig = ProtocolFeeConfig;
603
739
 
@@ -627,10 +763,12 @@ export declare interface ProtocolFeeConfig {
627
763
  }
628
764
 
629
765
  export declare enum ProtocolType {
766
+ PancakeV1 = "PancakeV1",
630
767
  PancakeV2 = "PancakeV2",
631
768
  PancakeV3 = "PancakeV3",
632
769
  PancakeInfinityCl = "Pancake_Infinity_Cl",
633
770
  PancakeInfinityLb = "Pancake_Infinity_Lb",
771
+ UniswapV2 = "UniswapV2",
634
772
  UniswapV3 = "UniswapV3",
635
773
  UniswapV4 = "UniswapV4",
636
774
  Dodo = "Dodo",
@@ -641,6 +779,7 @@ export declare enum ProtocolType {
641
779
  Apeswap = "Apeswap",
642
780
  BabyDogeSwap = "BabyDogeSwap",
643
781
  BabySwap = "BabySwap",
782
+ BakerySwap = "BakerySwap",
644
783
  PancakeStable = "Pancake_Stable",
645
784
  ListaStable = "Lista_Stable",
646
785
  SquadSwapV3 = "SquadSwap_V3",