@xzwiex/perk-swap-core
Version:
This npm package contains core logic of Perk Aggregator build on top of NEAR blockchain
3 lines • 50.6 kB
JavaScript
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("@tonic-foundation/token-list"),e=require("jsbi"),n=require("bn.js"),o=require("near-api-js"),i=require("@perk/concentrated-liquidity"),a=require("decimal.js"),r=require("near-api-js/lib/providers/json-rpc-provider"),u=require("near-units"),s=require("near-api-js/lib/transaction"),p=require("near-api-js/lib/utils/rpc_errors"),c=require("near-api-js/lib/utils"),l=require("near-api-js/lib/key_stores"),d=require("near-api-js/lib/providers/provider"),m=require("near-api-js/lib/constants");function f(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var g=f(e),h=f(n),w=f(a);const I=g.default.BigInt(0),y="v1.orderbook.near",k="150000000000000";var _;exports.SwapMode=void 0,(_=exports.SwapMode||(exports.SwapMode={})).ExactIn="ExactIn",_.ExactOut="ExactOut";const S=g.default.BigInt(10),v=(t,e)=>{const n=e instanceof g.default?e:g.default.BigInt(e),o=g.default.exponentiate(S,n);return g.default.multiply(t,o)},M=(t,e)=>{const n=e instanceof g.default?e:g.default.BigInt(e),o=g.default.exponentiate(S,n);return g.default.divide(t,o)},A=(t,e,n)=>M(v(t,n),e),O=(t,e)=>t.reduce(((t,n,o)=>t.set(n,e[o])),new Map),b=t=>O(t.token_account_ids,t.amounts.map((t=>g.default.BigInt(t)))),P=t=>O(t.token_account_ids,t.c_amounts.map((t=>g.default.BigInt(t)))),q=t=>{const e=(t=>t.filter((t=>"0"!==t.shares_total_supply)))(t),n=(t=>{const e=t.reduce(((t,e)=>{const n=e.token_account_ids.sort(),o=`${n[0]}_${n[1]}`;if(t.has(o)){const n=t.get(o)||[];t.set(o,[...n,e])}else t.set(o,[e]);return t}),new Map);return Array.from(e.values()).flatMap((t=>t.sort(((t,e)=>{const[n,o]=t.token_account_ids;return g.default.greaterThan(g.default.BigInt(e.reserves.get(n)||I),g.default.BigInt(t.reserves.get(n)||I))&&g.default.greaterThan(g.default.BigInt(e.reserves.get(o)||I),g.default.BigInt(t.reserves.get(o)||I))?1:-1}))[0]))})(e.filter((t=>"SIMPLE_POOL"===t.pool_kind)));return n},E=(t,e)=>({...t,id:e,reserves:b(t)}),B=async({provider:t,ammId:e,poolId:n})=>{const o=await t.query({request_type:"call_function",account_id:e,method_name:"get_pool",args_base64:Buffer.from(JSON.stringify({pool_id:n})).toString("base64"),finality:"optimistic"}).then((t=>JSON.parse(Buffer.from(t.result).toString())));return E(o,n)},T=async({provider:t,ammId:e,poolId:n,poolKind:o})=>{if(!o)return await B({provider:t,ammId:e,poolId:n});switch(o){case"STABLE_SWAP":return await F(t,e,n);case"RATED_SWAP":return await L(t,e,n);default:return await B({provider:t,ammId:e,poolId:n})}},x=async({provider:t,ammId:e,index:n=0,limit:o})=>await t.query({request_type:"call_function",account_id:e,method_name:"get_pools",args_base64:Buffer.from(JSON.stringify({from_index:n,limit:o})).toString("base64"),finality:"optimistic"}).then((t=>JSON.parse(Buffer.from(t.result).toString())));async function F(t,e,n){return o=await t.query({request_type:"call_function",account_id:e,method_name:"get_stable_pool",args_base64:Buffer.from(JSON.stringify({pool_id:n})).toString("base64"),finality:"optimistic"}).then((t=>JSON.parse(Buffer.from(t.result).toString()))),i=n,{...o,id:i,reserves:b(o),cAmountReserves:P(o),decimals:O(o.token_account_ids,o.decimals),rates:O(o.token_account_ids,o.c_amounts.map((()=>v(g.default.BigInt(1),18)))),pool_kind:"STABLE_SWAP"};var o,i}async function L(t,e,n){return((t,e)=>({...t,id:e,reserves:b(t),cAmountReserves:P(t),decimals:O(t.token_account_ids,t.decimals),rates:O(t.token_account_ids,t.rates.map((t=>g.default.BigInt(t)))),pool_kind:"RATED_SWAP"}))(await t.query({request_type:"call_function",account_id:e,method_name:"get_rated_pool",args_base64:Buffer.from(JSON.stringify({pool_id:n})).toString("base64"),finality:"optimistic"}).then((t=>JSON.parse(Buffer.from(t.result).toString()))),n)}const N=async({provider:t,ammId:e})=>{const n=await(async({provider:t,ammId:e})=>await t.query({request_type:"call_function",account_id:e,method_name:"get_number_of_pools",args_base64:Buffer.from(JSON.stringify({})).toString("base64"),finality:"optimistic"}).then((t=>JSON.parse(Buffer.from(t.result).toString()))))({provider:t,ammId:e});let o=0,i=[];for(;n>o;){const n=x({provider:t,ammId:e,index:o,limit:500});i.push(n),o+=500}const a=(await Promise.all(i)).flat().map(((t,e)=>E(t,e))),r=a.filter((t=>"SIMPLE_POOL"===t.pool_kind)),u=a.filter((t=>"SIMPLE_POOL"!==t.pool_kind));return{simplePools:r,stablePools:await Promise.all(u.map((n=>"STABLE_SWAP"===n.pool_kind?F(t,e,n.id):L(t,e,n.id))))}};async function R({user:t,swapSteps:e}){const n=[],o=e.map(((t,e,n)=>{const{amm:o,inputMint:i,outputMint:a,amountIn:r,minAmountOut:u}=t,s={pool_id:o.instanceId,token_in:i,token_out:a};return n.length>1?0===e?{...s,amount_in:r.toString(),min_amount_out:"0"}:{pool_id:o.instanceId,token_in:i,token_out:a,min_amount_out:u.toString()}:{...s,amount_in:r.toString(),min_amount_out:u.toString()}})),{amm:i,inputMint:a,amountIn:r}=e[0];return n.push({receiverId:a,signerId:t,actions:[{type:"FunctionCall",params:{methodName:"ft_transfer_call",args:{receiver_id:i.contractId,amount:r.toString(),msg:JSON.stringify({force:0,actions:o,referral_id:"95c9554eab0003879a571bc4c24f1ab8e30e1f698929c1be61e6a66770358b0f"}),memo:"perk"},gas:k,deposit:"1"}}]}),n}const C=g.default.BigInt(1e4);function D({reserves:t,poolFee:e=0,slippage:n,inputMint:o,outputMint:i,inputAmount:a}){const r=t.get(o)||I,u=t.get(i)||I;if(g.default.equal(r,I)||g.default.equal(u,I))return{amountIn:a,amountOut:I,minAmountOut:I,feeAmount:I,notEnoughLiquidity:!0,priceImpact:0};const s=g.default.divide(g.default.multiply(g.default.BigInt(e),a),C),p=g.default.subtract(a,s),c=g.default.multiply(p,u),l=g.default.add(r,p),d=g.default.divide(c,l),m=n.getFor(d),f=+r.toString()/+u.toString(),h=+a.toString()/+d.toString();return{notEnoughLiquidity:!1,amountIn:a,amountOut:d,minAmountOut:m,feeAmount:s,priceImpact:(h-f)/h}}function j({reserves:t,poolFee:e=0,slippage:n,inputMint:o,outputMint:i,outputAmount:a}){const r=t.get(o)||I,u=t.get(i)||I;if(g.default.equal(r,I)||g.default.equal(u,I))return{amountIn:I,amountOut:a,minAmountOut:a,feeAmount:I,notEnoughLiquidity:!0,priceImpact:0};const s=g.default.multiply(a,r),p=g.default.subtract(u,a),c=g.default.divide(s,p),l=g.default.divide(g.default.multiply(g.default.BigInt(e),c),C),d=g.default.add(c,l),m=g.default.divide(g.default.multiply(a,n.numerator),n.denominator),f=g.default.subtract(a,m),h=+r.toString()/+u.toString(),w=+d.toString()/+a.toString();return{notEnoughLiquidity:!1,amountIn:d,amountOut:a,minAmountOut:f,feeAmount:l,priceImpact:(w-h)/w}}function K({tokenInId:t,tokenOutId:e,slippage:n,amountIn:o,stablePool:i}){const a="STABLE_SWAP"===i.pool_kind?18:24,r=i.decimals.get(t)||null,u=i.decimals.get(e)||null;if(null===r||null===u)throw console.error({inputTokenDecimals:r,outputTokenDecimals:u,stablePool:i,tokenInId:t,tokenOutId:e}),new Error("No info about decimals of tokens");const s=Array.from(i.cAmountReserves.entries()).map((([t,e])=>{const n=i.rates.get(t)||null;if(!n)throw new Error("No rate for token");return[t,M(g.default.multiply(e,n),a)]})).reduce(((t,[e,n])=>t.set(e,n)),new Map),p={...i,cAmountReserves:s},c=A(o,r,a),l=s.get(t)||I,d=s.get(e)||I;if(g.default.equal(l,I)||g.default.equal(d,I))return{amountIn:o,amountOut:I,minAmountOut:I,feeAmount:I,notEnoughLiquidity:!0,priceImpact:0};const[m,f]=function({pool:t,tokenInId:e,tokenOutId:n,amountIn:o}){const i=t.cAmountReserves.get(e)||"0",a=(({pool:t,x_c_amount:e,tokenInId:n,tokenOutId:o})=>{const i=t.cAmountReserves.size,a=t.amp*i**i,r=(({pool:t})=>{const{amp:e,cAmountReserves:n}=t,o=n.size,i=Array.from(n.values()).map((t=>+t.toString())),a=i.reduce(((t,e)=>t+e),0);let r=0,u=a;for(let t=0;t<256;t++){let t=u;for(const e of i)t=t*u/(e*o);r=u;const n=e*o**o;if(u=r*(t*o+n*a)/(r*(n-1)+t*(o+1)),Math.abs(u-r)<=1)break}return u})({pool:t});let u=e,s=r*r/e;for(const[e,i]of t.cAmountReserves)if(e!==n&&e!==o){const t=+i.toString();u+=t,s=s*r/t}s=s*r/(a*i**i);const p=r/a+u;let c=0,l=r;for(let t=0;t<256&&(c=l,l=(l**2+s)/(2*l+p-r),!(Math.abs(l-c)<=1));t++);return l})({pool:t,x_c_amount:+g.default.add(o,g.default.BigInt(i)).toString(),tokenInId:e,tokenOutId:n}),r=t.cAmountReserves.get(n)||"0",u=g.default.BigInt(+r.toString()-a),s=(p=u,c=g.default.BigInt(t.total_fee),g.default.divide(g.default.multiply(p,c),g.default.BigInt(1e4)));var p,c;return[g.default.subtract(u,s),s]}({tokenInId:t,amountIn:c,tokenOutId:e,pool:p}),h=i.rates.get(t)||null,w=i.rates.get(e)||null;if(!h||!w)throw new Error("No rate for in or out token");const y=g.default.divide(v(m,a),w),k=g.default.divide(v(f,a),w),_=A(y,a,u),S=A(k,a,u),O=n.getFor(_),b=+w.toString()/+h.toString(),P=+c.toString()/+m.toString();return{notEnoughLiquidity:!1,amountIn:o,amountOut:_,minAmountOut:O,feeAmount:S,priceImpact:(P-b)/P}}const J=t=>{const{stablePool:e,tokenInId:n,tokenOutId:o,outputAmount:i,slippage:a,appproxInputAmount:r,minAmountMultiplier:u=0,maxAmountMultiplier:s=2,numberOfSteps:p=200}=t,c=(t=>{const{stablePool:e,tokenInId:n,tokenOutId:o,slippage:i,minAmount:a,maxAmount:r,numberOfSteps:u=200}=t,s=g.default.divide(g.default.subtract(r,a),g.default.BigInt(u));return Array.from(Array(u).keys()).map((t=>t+1)).map((t=>{const r=g.default.add(a,g.default.multiply(s,g.default.BigInt(t))),{notEnoughLiquidity:u,amountOut:p,minAmountOut:c,feeAmount:l,priceImpact:d}=K({amountIn:r,tokenOutId:o,tokenInId:n,slippage:i,stablePool:e});return{priceImpact:d,notEnoughLiquidity:u,amountIn:r,amountOut:p,minAmountOut:c,feeAmount:l}}))})({stablePool:e,tokenInId:n,tokenOutId:o,slippage:a,minAmount:M(g.default.multiply(r,g.default.BigInt(1e3*u)),3),maxAmount:M(g.default.multiply(r,g.default.BigInt(1e3*s)),3),numberOfSteps:p});return c.map((t=>{const{amountOut:e}=t,n=g.default.subtract(e,i),o=g.default.lessThan(n,I)?g.default.unaryMinus(n):n;return{...t,swapAmountOutDiff:o}})).sort(((t,e)=>g.default.equal(t.swapAmountOutDiff,e.swapAmountOutDiff)?0:g.default.lessThan(t.swapAmountOutDiff,e.swapAmountOutDiff)?-1:1))[0]},U=({tokenInId:t,tokenOutId:e,amountOut:n,slippage:o,stablePool:i})=>{const a=n;let r=null;for(let u=0;u<2;u+=1)r=J(r?{stablePool:i,tokenInId:t,tokenOutId:e,slippage:o,outputAmount:n,appproxInputAmount:r.amountIn,minAmountMultiplier:.95,maxAmountMultiplier:1.05,numberOfSteps:200}:{stablePool:i,tokenInId:t,tokenOutId:e,slippage:o,outputAmount:n,appproxInputAmount:a,numberOfSteps:200});if(!r)throw new Error("No best option for getInputAmount");return r};class ${constructor(t){this.id=void 0,this.contractId=void 0,this.instanceId=void 0,this.label=void 0,this.pool=void 0,this.isSimplePool=void 0,this.reserves=void 0,this.label="Jumbo",this.id=`${t.id}`,this.contractId="v1.jumbo_exchange.near",this.instanceId=t.id,this.pool=t,this.isSimplePool="SIMPLE_POOL"===t.pool_kind,this.reserves=t.reserves}static async loadPools({provider:t}){try{const{simplePools:e,stablePools:n}=await N({provider:t,ammId:"v1.jumbo_exchange.near"});return[...q(e),...n].map((t=>new $(t)))}catch(t){console.log("Error loading pools for Ref Finance",t)}return[]}getQuote(t){const{inputMint:e,outputMint:n,amount:o,slippage:i,swapMode:a}=t,r=this.pool.total_fee/1e4;if(a===exports.SwapMode.ExactIn){if(this.isSimplePool){const{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feeAmount:p,priceImpact:c}=D({reserves:this.pool.reserves,poolFee:this.pool.total_fee,inputMint:e,outputMint:n,inputAmount:o,slippage:i});return{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feePct:r,feeMint:e,feeAmount:p,priceImpact:c}}{const{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feeAmount:p,priceImpact:c}=K({tokenInId:e,tokenOutId:n,slippage:i,stablePool:this.pool,amountIn:o});return{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feePct:r,feeMint:e,feeAmount:p,priceImpact:c}}}if(a===exports.SwapMode.ExactOut){if(this.isSimplePool){const{amountIn:t,amountOut:a,minAmountOut:u,feeAmount:s,priceImpact:p,notEnoughLiquidity:c}=j({reserves:this.pool.reserves,poolFee:this.pool.total_fee,inputMint:e,outputMint:n,outputAmount:o,slippage:i});return{notEnoughLiquidity:c,amountIn:t,amountOut:a,minAmountOut:u,feePct:r,feeMint:e,feeAmount:s,priceImpact:p}}{const{notEnoughLiquidity:t,feeAmount:a,amountIn:u,amountOut:s,minAmountOut:p,priceImpact:c}=U({tokenInId:e,tokenOutId:n,slippage:i,stablePool:this.pool,amountOut:o});return{notEnoughLiquidity:t,amountIn:u,amountOut:s,minAmountOut:p,feePct:r,feeMint:e,feeAmount:a,priceImpact:c}}}throw new Error("Unknown swap mode type")}async getPromiseForUpdate({provider:t}){return T({provider:t,ammId:this.contractId,poolId:this.instanceId,poolKind:this.pool.pool_kind}).then((t=>{this.pool=t}))}async createSwapInstructions(t){const{user:e,swapStep:n}=t,o=await R({user:e,swapSteps:[n]});return console.log("swapTransactions",o),o}async createSwapRouteInstructions(t){const{user:e,swapRoute:n}=t,o=await R({user:e,swapSteps:n.steps});return console.log("swapTransactions",o),o}get reserveTokenMints(){return this.pool.token_account_ids}}const z=({perkLiquidity:t,pool:e,positions:n})=>{const{spacing:o}=e,i=n.reduce(((t,e)=>{const{lower_index:n,upper_index:i,total_liquidity:a}=e,r=Math.abs(i-n)/o,u=a;for(let e=0;e<=r;e++){const i=n+o*e;t.has(i)?t.set(i,(t.get(i)||0)+u):t.set(i,u)}return t}),new Map);return Array.from(i.entries()).map((e=>{const n=t.math.getPriceFromTick({tick:e[0],spacing:o}),i=Math.floor(e[1]);return{tick:e[0],actualPrice:n,sqrtActualPrice:Math.sqrt(n),liquidity:i}})).sort(((t,e)=>t.tick-e.tick))},Q=g.default.BigInt(1e6);class W{constructor(t,e){this.id=void 0,this.contractId=void 0,this.instanceId=void 0,this.label=void 0,this.pool=void 0,this.positions=void 0,this.perkLiquiditySDK=void 0,this.label="Perk",this.id=`${t.pool_id}`,this.contractId="dev-perk-conliq2.near",this.instanceId=t.pool_id,this.pool=t,this.positions=[],this.perkLiquiditySDK=e}static async loadPools({provider:t}){try{const e=await i.PerkLiquidity.load({provider:t});return(t=>{const e=t.reduce(((t,e)=>{const n=[e.alpha_id,e.beta_id].sort(),o=`${n[0]}_${n[1]}-${e.pool_fee_tier}`;if(t.has(o)){const n=t.get(o)||[];t.set(o,[...n,e])}else t.set(o,[e]);return t}),new Map);return Array.from(e.values()).flatMap((t=>t.sort(((t,e)=>g.default.greaterThan(g.default.BigInt(e.liquidity||I),g.default.BigInt(t.liquidity||I))?1:-1))[0]))})(await e.fetchers.loadPools()).map((t=>new W(t,e)))}catch(t){console.log("Error loading pools for Ref Finance",t)}return[]}getQuote(t){const{inputMint:e,outputMint:n,amount:o,slippage:i,swapMode:a}=t,r=this.pool.pool_fee_tier;if(a===exports.SwapMode.ExactIn){const{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feeAmount:p,priceImpact:c}=function({positions:t,perkLiquiditySDK:e,pool:n,slippage:o,inputMint:i,inputAmount:a}){const r=z({pool:n,positions:t,perkLiquidity:e});if(0===r.length)return{amountIn:a,amountOut:I,minAmountOut:I,feeAmount:I,notEnoughLiquidity:!0,priceImpact:0};const u=i===n.alpha_id?"below":"above",s=r.filter((t=>"below"===u?t.actualPrice<n.current_price:t.actualPrice>n.current_price)).sort(((t,e)=>"below"===u?e.actualPrice-t.actualPrice:t.actualPrice-e.actualPrice));console.log("filteredTicks",s);const p=g.default.divide(g.default.multiply(g.default.BigInt(1e6*n.pool_fee_tier),a),Q);let c=g.default.subtract(a,p),l=I,d=n.current_price;for(const t of s)if(!g.default.equal(c,I)){if(i===n.alpha_id){const n=e.math.getBetaAmountFromLiquidity({liquidity:t.liquidity,currentPrice:d,lowerPrice:t.actualPrice}),o=g.default.BigInt(new w.default(n).div(t.actualPrice).floor());if(console.log({tickData:t,currentPrice:d,betaAmountInTick:n,remainingInputAmount:c.toString(),inputAmountToReduce:o.toString()}),g.default.greaterThanOrEqual(o,c)){const e=g.default.BigInt(new w.default(c.toString()).mul(t.actualPrice).floor());c=I,l=g.default.add(l,e)}else c=g.default.subtract(c,g.default.BigInt(o)),l=g.default.add(l,g.default.BigInt(new w.default(n).floor()))}else{const n=e.math.getAlphaAmountFromLiquidity({liquidity:t.liquidity,currentPrice:d,upperPrice:t.actualPrice}),o=g.default.BigInt(new w.default(n).mul(t.actualPrice).floor());if(g.default.greaterThanOrEqual(o,c)){const e=g.default.BigInt(new w.default(c.toString()).div(t.actualPrice).floor());c=I,l=g.default.add(l,e)}else c=g.default.subtract(c,g.default.BigInt(o)),l=g.default.add(l,g.default.BigInt(new w.default(n).floor()))}d=t.actualPrice}const m=o.getFor(l),f=i===n.alpha_id?+l.toString()/+a.toString():+a.toString()/+l.toString(),h=Math.abs(f-n.current_price)/f;return console.log({remainingInputAmount:c.toString(),inputAmount:a.toString(),outputAmount:l.toString(),newPrice:f,currentPrice:d,pool:n.current_price,priceImpact:h}),{notEnoughLiquidity:g.default.greaterThan(c,I),amountIn:a,amountOut:l,minAmountOut:m,feeAmount:p,priceImpact:h}}({positions:this.positions,pool:this.pool,perkLiquiditySDK:this.perkLiquiditySDK,inputMint:e,outputMint:n,inputAmount:o,slippage:i});return{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feePct:r,feeMint:e,feeAmount:p,priceImpact:c}}if(a===exports.SwapMode.ExactOut){const{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feeAmount:p,priceImpact:c}=function({positions:t,perkLiquiditySDK:e,pool:n,slippage:o,inputMint:i,outputAmount:a}){const r=z({pool:n,positions:t,perkLiquidity:e});if(0===r.length)return{amountIn:I,amountOut:a,minAmountOut:a,feeAmount:I,notEnoughLiquidity:!0,priceImpact:0};const u=i===n.alpha_id?"below":"above",s=r.filter((t=>"below"===u?t.actualPrice<n.current_price:t.actualPrice>n.current_price)).sort(((t,e)=>"below"===u?e.actualPrice-t.actualPrice:t.actualPrice-e.actualPrice));let p=I,c=a,l=n.current_price;for(const t of s)if(!g.default.equal(c,I)){if(i===n.alpha_id){const n=e.math.getBetaAmountFromLiquidity({liquidity:t.liquidity,currentPrice:l,lowerPrice:t.actualPrice}),o=g.default.BigInt(new w.default(n).floor()),i=g.default.BigInt(new w.default(n).div(t.actualPrice).ceil());if(g.default.greaterThanOrEqual(o,c)){const e=g.default.BigInt(new w.default(c.toString()).div(t.actualPrice).ceil());c=I,p=g.default.add(p,e)}else c=g.default.subtract(c,o),p=g.default.add(p,i)}else{const n=e.math.getAlphaAmountFromLiquidity({liquidity:t.liquidity,currentPrice:l,upperPrice:t.actualPrice}),o=g.default.BigInt(new w.default(n).floor()),i=g.default.BigInt(new w.default(n).mul(t.actualPrice).ceil());if(g.default.greaterThanOrEqual(o,c)){const e=g.default.BigInt(new w.default(c.toString()).mul(t.actualPrice).ceil());c=I,p=g.default.add(p,e)}else c=g.default.subtract(c,o),p=g.default.add(p,i)}l=t.actualPrice}const d=g.default.divide(g.default.multiply(g.default.BigInt(1e6*n.pool_fee_tier),p),Q),m=g.default.add(p,d),f=o.getFor(a),h=i===n.alpha_id?+a.toString()/+p.toString():+p.toString()/+a.toString(),y=Math.abs(h-n.current_price)/h;return{notEnoughLiquidity:g.default.greaterThan(c,I),amountIn:m,amountOut:a,minAmountOut:f,feeAmount:d,priceImpact:y}}({positions:this.positions,pool:this.pool,perkLiquiditySDK:this.perkLiquiditySDK,inputMint:e,outputMint:n,outputAmount:o,slippage:i});return{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feePct:r,feeMint:e,feeAmount:p,priceImpact:c}}throw new Error("Unknown swap mode type")}async getPromiseForUpdate(){return Promise.all([this.perkLiquiditySDK.fetchers.loadPool(this.pool.pool_id).then((t=>{this.pool=t})),this.perkLiquiditySDK.fetchers.getPoolsPositions([this.pool.pool_id]).then((t=>{this.positions=Array.from(t.values()).flat()}))]).then((()=>{}))}async createSwapInstructions(t){const{swapStep:e,user:n}=t,o=await this.perkLiquiditySDK.instructions.getSwapTransactions({user:n,pool_id:e.amm.instanceId,input_token:e.inputMint,output_token:e.outputMint,input_amount:e.amountIn.toString(),output_amount:e.amountOut.toString()});return console.log("swapTransactions",o),o}async createSwapRouteInstructions(t){const{swapRoute:e,user:n}=t,o=e.steps.map((t=>({pool_id:t.amm.instanceId,input_token:t.inputMint,output_token:t.outputMint,input_amount:t.amountIn.toString(),output_amount:t.amountOut.toString()}))),i=await this.perkLiquiditySDK.instructions.getMultiSwapTransactions({user:n,steps:o});return console.log("swapTransactions",i),i}get reserveTokenMints(){return[this.pool.alpha_id,this.pool.beta_id]}}class G{constructor(t){this.id=void 0,this.contractId=void 0,this.instanceId=void 0,this.pool=void 0,this.isSimplePool=void 0,this.label=void 0,this.label="Ref.Finance",this.id=`${t.id}`,this.contractId="v2.ref-finance.near",this.instanceId=t.id,this.pool=t,this.isSimplePool="SIMPLE_POOL"===t.pool_kind}static async loadPools({provider:t}){try{const{simplePools:e,stablePools:n}=await N({provider:t,ammId:"v2.ref-finance.near"});return[...q(e),...n].map((t=>new G(t)))}catch(t){console.log("Error loading pools for Ref Finance",t)}return[]}getQuote(t){const{inputMint:e,outputMint:n,amount:o,slippage:i,swapMode:a}=t,r=this.pool.total_fee/1e4;if(a===exports.SwapMode.ExactIn){if(this.isSimplePool){const{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feeAmount:p,priceImpact:c}=D({reserves:this.pool.reserves,poolFee:this.pool.total_fee,inputMint:e,outputMint:n,inputAmount:o,slippage:i});return{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feePct:r,feeMint:e,feeAmount:p,priceImpact:c}}{const{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feeAmount:p,priceImpact:c}=K({tokenInId:e,tokenOutId:n,slippage:i,stablePool:this.pool,amountIn:o});return{notEnoughLiquidity:t,amountIn:a,amountOut:u,minAmountOut:s,feePct:r,feeMint:e,feeAmount:p,priceImpact:c}}}if(a===exports.SwapMode.ExactOut){if(this.isSimplePool){const{amountIn:t,amountOut:a,minAmountOut:u,feeAmount:s,priceImpact:p,notEnoughLiquidity:c}=j({reserves:this.pool.reserves,poolFee:this.pool.total_fee,inputMint:e,outputMint:n,outputAmount:o,slippage:i});return{notEnoughLiquidity:c,amountIn:t,amountOut:a,minAmountOut:u,feePct:r,feeMint:e,feeAmount:s,priceImpact:p}}{const{notEnoughLiquidity:t,feeAmount:a,amountIn:u,amountOut:s,minAmountOut:p,priceImpact:c}=U({tokenInId:e,tokenOutId:n,slippage:i,stablePool:this.pool,amountOut:o});return{notEnoughLiquidity:t,amountIn:u,amountOut:s,minAmountOut:p,feePct:r,feeMint:e,feeAmount:a,priceImpact:c}}}throw new Error("Unknown swap mode type")}async getPromiseForUpdate({provider:t}){return T({provider:t,ammId:this.contractId,poolId:this.instanceId,poolKind:this.pool.pool_kind}).then((t=>{this.pool=t}))}async createSwapInstructions(t){const{user:e,swapStep:n}=t,o=await R({user:e,swapSteps:[n]});return console.log("swapTransactions",o),o}async createSwapRouteInstructions(t){const{user:e,swapRoute:n}=t,o=await R({user:e,swapSteps:n.steps});return console.log("swapTransactions",o),o}get reserveTokenMints(){return this.pool.token_account_ids}}class H{constructor(t,e){this.numerator=void 0,this.denominator=void 0,this.toString=()=>`${this.numerator.toString()}/${this.denominator.toString()}`,this.numerator=t,this.denominator=e}static fromSlippageNumber(t){return new H(g.default.BigInt(1e4*t),g.default.BigInt(1e6))}static fromFeeBpsNumber(t){return new H(g.default.BigInt(t),g.default.BigInt(1e5))}getFor(t){const e=g.default.BigInt(this.numerator.toString()),n=g.default.BigInt(this.denominator.toString());return g.default.divide(g.default.multiply(t,g.default.subtract(n,e)),n)}getFrom(t){const e=g.default.BigInt(this.numerator.toString()),n=g.default.BigInt(this.denominator.toString());return g.default.divide(g.default.multiply(t,e),n)}}const V=async({provider:t,tokenId:e,tokenOwnerId:n})=>{if(!e||!n)return console.error("No token id or token owner id for loading account storage balance",`tokenId: ${e}`,`tokenOwnerId: ${n}`),{tokenId:e,existing:!1,storageBalance:null};const o=await t.query({request_type:"call_function",account_id:e,method_name:"storage_balance_of",args_base64:Buffer.from(JSON.stringify({account_id:n})).toString("base64"),finality:"optimistic"}).then((t=>JSON.parse(Buffer.from(t.result).toString())));return{tokenId:e,existing:null!==o,storageBalance:o}};async function X(t,e,n){const o=new Array,{storageBalance:i}=await V({provider:t,tokenId:e,tokenOwnerId:n});if(!i)return o.push({type:"FunctionCall",params:{methodName:"storage_deposit",args:{registration_only:!0,account_id:n},gas:k,deposit:"100000000000000000000000"}}),{receiverId:e,signerId:n,actions:o}}const Y=async(t,e)=>{const n=new Array,o=await X(t.connection.provider,"wrap.near",t.accountId);let i=e;if(o)n.push(...o.actions);else{const n=await t.viewFunction("wrap.near","ft_balance_of",{account_id:t.accountId});if(g.default.greaterThanOrEqual(g.default.BigInt(n),i))return[];console.log("NEAR account found, balance:",n),i=g.default.subtract(e,g.default.BigInt(n))}return n.push({type:"FunctionCall",params:{methodName:"near_deposit",args:{},gas:k,deposit:i.toString()}}),n},Z=async t=>{const e=new Array,n=t.toString();return e.push({type:"FunctionCall",params:{methodName:"near_withdraw",args:{amount:n},gas:k,deposit:"1"}}),e},tt=async(t,e)=>({receiverId:"wrap.near",signerId:t,actions:await Z(e)}),et=async t=>{const{provider:e,accountId:n,method:o,args:i={}}=t,a=await e.query({request_type:"call_function",account_id:n,method_name:o,args_base64:Buffer.from(JSON.stringify(i)).toString("base64"),finality:"optimistic"});return JSON.parse(Buffer.from(a.result).toString())};class nt{constructor(t){this.rawMarket=void 0,this.label="Spin Finance",this.id=void 0,this.reserveTokenMints=void 0,this.contractId="spot.spin-fi.near",this.instanceId=void 0,this.orderBook=void 0,this.rawMarket=t,this.id=`${t.id}`,this.instanceId=t.id,this.reserveTokenMints=[t.base.address,t.quote.address].map((t=>"near.near"===t?"wrap.near":t))}static async loadUserDeposits({user:t,provider:e}){return await et({provider:e,accountId:"spot.spin-fi.near",method:"get_deposits",args:{account_id:t}})}static createWithdrawFromDepositsTransaction({user:t,token:e,amount:n}){const o="near.near"===e;return{receiverId:"spot.spin-fi.near",signerId:t,actions:[{type:"FunctionCall",params:{methodName:"withdraw",args:{token:o?"near.near":e,amount:n},gas:k,deposit:o?"0":"1"}}]}}async createSwapInstructions(t){const{user:e,swapStep:n,provider:o}=t,i=[],a=await nt.loadUserDeposits({user:e,provider:o}),r=g.default.BigInt(a["wrap.near"===n.inputMint?"near.near":n.inputMint]||"0"),{address:u}=this.rawMarket.base,{address:s}=this.rawMarket.quote,p=u===n.inputMint||"near.near"===u&&"wrap.near"===n.inputMint,c="near.near"===u||"near.near"===s;if(g.default.lessThan(r,n.amountIn)){const t=g.default.subtract(n.amountIn,r);c&&"wrap.near"===n.inputMint?(i.push(await tt(e,t)),i.push({receiverId:"spot.spin-fi.near",signerId:e,actions:[{type:"FunctionCall",params:{methodName:"deposit_near",args:{},gas:k,deposit:t.toString()}}]})):i.push({receiverId:n.inputMint,signerId:e,actions:[{type:"FunctionCall",params:{methodName:"ft_transfer_call",args:{receiver_id:"spot.spin-fi.near",amount:t.toString(),msg:""},gas:k,deposit:"1"}}]})}const l=p?"place_ask":"place_bid",d=10**this.rawMarket.quote.decimal,m=new w.default(this.rawMarket.limits.step_size);let f=new w.default((p?n.amountIn:n.minAmountOut).toString()).div(m).floor().mul(m);p||(f=f.add(n.feeAmount.toString()).div(m).ceil().mul(m));const h=new w.default((p?n.minAmountOut:n.amountIn).toString()).div(d),I=new w.default(this.rawMarket.limits.tick_size),y=h.mul(d).div(I).div(f.div(10**this.rawMarket.base.decimal)).floor().mul(I);i.push({receiverId:"spot.spin-fi.near",signerId:e,actions:[{type:"FunctionCall",params:{methodName:l,args:{market_id:this.rawMarket.id,price:y.ceil().toFixed(0),quantity:f.toFixed(0),market_order:!0,memo:"perk"},gas:k,deposit:"0"}}]});const _=n.minAmountOut.toString();return i.push(nt.createWithdrawFromDepositsTransaction({user:e,token:"wrap.near"===n.outputMint?"near.near":n.outputMint,amount:_})),c&&"wrap.near"===n.outputMint&&i.push({receiverId:"wrap.near",signerId:e,actions:[{type:"FunctionCall",params:{methodName:"near_deposit",args:{},gas:k,deposit:_}}]}),i}async createSwapRouteInstructions(t){const{provider:e,user:n,swapRoute:o}=t,i=[];for(let t of o.steps){const o=await t.amm.createSwapInstructions({provider:e,user:n,swapStep:t});i.push(...o)}return i}async getPromiseForUpdate({provider:t}){try{const e=await et({provider:t,accountId:"spot.spin-fi.near",method:"get_orderbook",args:{market_id:this.rawMarket.id,limit:100}});this.orderBook=e}catch(t){console.log("error getPromiseForUpdate spin for market",this.rawMarket.id)}}getQuote(t){if(!this.orderBook)throw new Error(`Order book for market ${this.rawMarket.ticker} is not loaded`);const e=t.inputMint===this.rawMarket.base.address||"wrap.near"===t.inputMint&&"near.near"===this.rawMarket.base.address,n=e?this.orderBook.bid_orders:this.orderBook.ask_orders,o=e&&t.swapMode===exports.SwapMode.ExactIn||!e&&t.swapMode===exports.SwapMode.ExactOut;let i=new w.default(t.amount.toString()),a=new w.default(0),r=new w.default(0);const u=new w.default(10).pow(this.rawMarket.base.decimal),s=new w.default(this.rawMarket.limits.step_size),p=new w.default(this.rawMarket.fees.taker_fee).div(10**this.rawMarket.fees.decimals);for(const c of n){const n=new w.default(c.price),l=o?i.div(s).floor().mul(s):i.mul(u).div(n).div(s).floor().mul(s),d=new w.default(c.quantity),m=w.default.min(l,d),f=m.mul(n).div(u);a=a.add(e?m:f),r=r.add(e?f:m);const h=r.mul(p),I=r.sub(h).floor();let y=new w.default(t.slippage.getFor(g.default.BigInt(I.floor().toString())).toString());if(e||(y=y.div(s).floor().mul(s)),i=i.sub(o?m:f),m.lessThanOrEqualTo(0)){const n=e?a:y,o=e?y:a,i=n.greaterThanOrEqualTo(new w.default(this.rawMarket.limits.min_base_quantity)),r=n.lessThanOrEqualTo(new w.default(this.rawMarket.limits.max_base_quantity)),u=o.greaterThanOrEqualTo(new w.default(this.rawMarket.limits.min_quote_quantity)),s=o.lessThanOrEqualTo(new w.default(this.rawMarket.limits.max_quote_quantity));return{amountIn:g.default.BigInt(a.floor().toString()),amountOut:g.default.BigInt(I.floor().toString()),minAmountOut:g.default.BigInt(y.floor().toString()),feeAmount:g.default.BigInt(h.floor().toString()),feeMint:t.outputMint,feePct:parseFloat(this.rawMarket.fees.taker_fee)/10**this.rawMarket.base.decimal,notEnoughLiquidity:!(i&&r&&u&&s),priceImpact:0}}}const c=r.mul(p);return{amountIn:g.default.BigInt(a.floor().toString()),amountOut:g.default.BigInt(r.sub(c).floor().toString()),minAmountOut:t.slippage.getFor(g.default.BigInt(r.floor().toString())),feeAmount:g.default.BigInt(c.floor().toString()),feeMint:t.inputMint,feePct:parseFloat(this.rawMarket.fees.taker_fee)/10**this.rawMarket.base.decimal,notEnoughLiquidity:!0,priceImpact:0}}static async loadMarkets(t){const{provider:e}=t;return(await et({accountId:"spot.spin-fi.near",method:"get_markets",provider:e})).map((t=>new nt(t)))}}const ot=(t,e,n=!1)=>n?t.div(e).ceil().mul(e):t.div(e).floor().mul(e);class it{constructor(t){this.market=void 0,this.label="Tonic",this.id=void 0,this.contractId=y,this.instanceId=void 0,this.reserveTokenMints=void 0,this.orderBook=void 0,this.market=t,this.id=this.market.id,this.instanceId=Math.round(1e6*Math.random()),this.orderBook=this.market.orderbook,this.reserveTokenMints=["ft"===this.market.base_token.token_type.type?this.market.base_token.token_type.account_id:"wrap.near","ft"===this.market.quote_token.token_type.type?this.market.quote_token.token_type.account_id:"wrap.near"]}async getPromiseForUpdate({provider:t}){const e=await et({accountId:y,method:"get_orderbook",args:{market_id:this.id,depth:128},provider:t});this.orderBook=e}resolveQuote(t){const{amountOut:e,amountIn:n,fee:o,slippage:i,stepSize:a,outputMint:r,notEnoughLiquidity:u,swapMode:s,isSellBase:p}=t,c=e.mul(o),l=e.sub(c).floor().toString(),d=g.default.BigInt(l),m=s===exports.SwapMode.ExactIn?n.floor():n.ceil(),f=p?ot(m,a.toString(),s===exports.SwapMode.ExactOut):m,h=p?new w.default(d.toString()):ot(new w.default(d.toString()),a.toString()),I=p?new w.default(i.getFor(d).toString()):ot(new w.default(i.getFor(d).toString()),a.toString());return{amountIn:g.default.BigInt(f.floor().toString()),amountOut:g.default.BigInt(h.floor().toString()),minAmountOut:g.default.BigInt(I.floor().toString()),feeAmount:g.default.BigInt(c.floor().toString()),feeMint:r,feePct:this.market.taker_fee_base_rate/1e4,notEnoughLiquidity:u,priceImpact:0}}getQuote(t){if(!this.orderBook)throw new Error(`Order book for market ${this.market.id} is not loaded`);const{inputMint:e,outputMint:n,amount:o,swapMode:i}=t,a="ft"===this.market.base_token.token_type.type&&e===this.market.base_token.token_type.account_id||"wrap.near"===e&&"near"===this.market.base_token.token_type.type,r=a?this.orderBook.bids:this.orderBook.asks,u=a&&i===exports.SwapMode.ExactIn||!a&&i===exports.SwapMode.ExactOut;let s=new w.default(o.toString());const p=new w.default(this.market.taker_fee_base_rate).div(1e4);t.swapMode===exports.SwapMode.ExactOut&&(s=s.mul(p.add(1)));let c=new w.default(0),l=new w.default(0);const d=new w.default(10).pow(this.market.base_token.decimals),m=new w.default(this.market.base_token.lot_size);for(const e of r){const o=new w.default(e.limit_price),i=u?s.div(m).floor().mul(m):s.mul(d).div(o),r=new w.default(e.open_quantity),f=w.default.min(i,r),g=f.mul(o).div(d);c=c.add(a?f:g),l=l.add(a?g:f),s=s.sub(u?f:g);const h=a?c:l,I=a?l:c;if(f.lessThanOrEqualTo(0))return this.resolveQuote({amountIn:c,amountOut:l,fee:p,stepSize:m,slippage:t.slippage,outputMint:n,notEnoughLiquidity:!h.greaterThanOrEqualTo(new w.default(this.market.base_token.lot_size))||!I.greaterThanOrEqualTo(new w.default(this.market.quote_token.lot_size)),swapMode:t.swapMode,isSellBase:a})}return this.resolveQuote({amountIn:c,amountOut:l,fee:p,stepSize:m,slippage:t.slippage,outputMint:n,notEnoughLiquidity:!0,swapMode:t.swapMode,isSellBase:a})}async createSwapInstructions(t){const e=[],{base_token:{token_type:{type:n}},quote_token:{token_type:{type:o}}}=this.market,{user:i,swapStep:{amountIn:a,minAmountOut:r,inputMint:u,outputMint:s}}=t,p="near"===n||"near"===o,c=p&&"wrap.near"===u,l=p&&"wrap.near"===s,d={action:"Swap",params:[{type:"Swap",market_id:this.market.id,side:"ft"===this.market.base_token.token_type.type&&u===this.market.base_token.token_type.account_id||"near"===this.market.base_token.token_type.type&&"wrap.near"===u?"Sell":"Buy",min_output_token:r.toString()}]};return c&&e.push(await tt(i,a)),e.push(c?{receiverId:y,signerId:t.user,actions:[{type:"FunctionCall",params:{methodName:"swap_near",args:{swaps:d.params},gas:k,deposit:a.toString()}}]}:{receiverId:u,signerId:t.user,actions:[{type:"FunctionCall",params:{methodName:"ft_transfer_call",args:{receiver_id:y,amount:a.toString(),msg:JSON.stringify(d),memo:"perk"},gas:k,deposit:"1"}}]}),l&&e.push({receiverId:"wrap.near",signerId:i,actions:[{type:"FunctionCall",params:{methodName:"near_deposit",args:{},gas:k,deposit:r.toString()}}]}),e}async createSwapRouteInstructions(t){const{provider:e,user:n,swapRoute:o}=t,i=[];for(let t of o.steps){const o=await t.amm.createSwapInstructions({provider:e,user:n,swapStep:t});i.push(...o)}return i}static async loadMarkets(t){const{provider:e}=t;return(await et({accountId:y,method:"list_markets",args:{from_index:0,limit:9999},provider:e})).filter((t=>"Active"===t.state)).map((t=>new it(t)))}}const at=async t=>[...await G.loadPools({provider:t}),...await $.loadPools({provider:t}),...await nt.loadMarkets({provider:t}),...await it.loadMarkets({provider:t}),...await W.loadPools({provider:t})];async function rt(t,e){const n=new Map;e.forEach((e=>{e.forEach((({amm:e})=>{n.set(`${e.label}-${e.id}`,e.getPromiseForUpdate({provider:t}))}))}));const o=Array.from(n.values());await Promise.all(o)}const ut=["Ref.Finance","Jumbo","Perk"],st=t=>t.length>1&&t[0].label===t[1].label&&!!t.every((t=>ut.some((e=>t.label===e)))),pt={steps:[],inputMint:"",outputMint:"",amountIn:I,amountOut:I,minAmountOut:I,swapMode:exports.SwapMode.ExactIn,notEnoughLiquidity:!0,priceImpact:0,depositAndNetworkFee:I,platformFee:{amount:I,token:"",pct:0}},ct=({routes:t,amount:e,swapMode:n=exports.SwapMode.ExactIn,inputMint:o,outputMint:i,feeBps:a,slippage:r,userTokensMap:u})=>{if(0===t.length)return[pt];const s=t=>g.default.greaterThan(t.amountIn,I)&&g.default.greaterThan(t.amountOut,I)&&g.default.greaterThan(t.steps[t.steps.length-1].amountOut,I)&&Math.abs(t.priceImpact)<.9&&!t.notEnoughLiquidity;if(n===exports.SwapMode.ExactIn){const p=t.map((t=>(({route:t,feeBps:e,swapMode:n,amountIn:o,slippage:i,inputMint:a,outputMint:r,userTokensMap:u})=>{const s=[],p=st(t.map((t=>t.amm)));let c=o,l=0;for(const{amm:e,inputToken:o,outputToken:a}of t){if(!e)return pt;const t=H.fromSlippageNumber(0),r=0===l&&p?t:i,{amountIn:u,amountOut:d,minAmountOut:m,feeAmount:f,feeMint:g,priceImpact:h,notEnoughLiquidity:w}=e.getQuote({inputMint:o,outputMint:a,amount:c,swapMode:n,slippage:r});s.push({amm:e,inputMint:o,outputMint:a,amountIn:u,amountOut:d,minAmountOut:m,feeAmount:f,feeMint:g,priceImpact:h,notEnoughLiquidity:w}),console.log("swapSteps",s),c=m,l++}const d=s.length>0?s[s.length-1].amountOut:I,m=e.getFrom(d),f=g.default.subtract(d,m),h=s.length>0?s[s.length-1].minAmountOut:I,w=s.some((t=>t.notEnoughLiquidity)),y=1-s.reduce(((t,e)=>t*(1-e.priceImpact)),1),_=s.reduce(((t,e)=>{const{existing:n}=u.get(e.outputMint)||{existing:!1};return n?t:g.default.add(t,g.default.BigInt("100000000000000000000000"))}),I),S=g.default.multiply(g.default.BigInt(k),g.default.BigInt(s.length));return{steps:s,amountIn:o,amountOut:f,minAmountOut:h,inputMint:a,outputMint:r,swapMode:n,notEnoughLiquidity:w,priceImpact:y,depositAndNetworkFee:g.default.add(_,S),platformFee:{amount:m,token:r,pct:+e.numerator.toString()/100}}})({route:t,amountIn:e,slippage:r,inputMint:o,outputMint:i,swapMode:n,feeBps:a,userTokensMap:u})));return p.filter(s).sort(((t,e)=>g.default.greaterThanOrEqual(e.amountOut,t.amountOut)?1:-1))}if(n===exports.SwapMode.ExactOut){const p=t.map((t=>(({route:t,feeBps:e,swapMode:n,amountOut:o,slippage:i,inputMint:a,outputMint:r,userTokensMap:u})=>{const s=[],p=st(t.map((t=>t.amm)));let c=o,l=0;const d=t.reverse();for(const{amm:t,inputToken:e,outputToken:o}of d){if(!t)return pt;const a=H.fromSlippageNumber(0),r=0===l&&p?a:i,{amountIn:u,amountOut:d,minAmountOut:m,feeAmount:f,feeMint:g,notEnoughLiquidity:h,priceImpact:w}=t.getQuote({inputMint:e,outputMint:o,amount:c,swapMode:n,slippage:r});s.push({amm:t,inputMint:e,outputMint:o,amountIn:u,amountOut:d,minAmountOut:m,feeAmount:f,feeMint:g,priceImpact:w,notEnoughLiquidity:h}),c=u,l++}const m=s.reverse().reduce(((t,e,n)=>{if(0===n)return t.push(e),t;const o={...e,amountIn:t[t.length-1].minAmountOut};return t.push(o),t}),[]),f=m.length>0?m[0].amountIn:I,h=m.length>0?m[m.length-1].minAmountOut:I,w=e.getFrom(f),y=g.default.add(f,w);m[0].amountIn=y;const _=s.some((t=>t.notEnoughLiquidity)),S=1-s.reduce(((t,e)=>t*(1-e.priceImpact)),1),v=m.reduce(((t,e)=>{const{existing:n}=u.get(e.outputMint)||{existing:!1};return n?t:g.default.add(t,g.default.BigInt("100000000000000000000000"))}),I),M=g.default.multiply(g.default.BigInt(k),g.default.BigInt(m.length));return{steps:m,amountIn:y,amountOut:o,minAmountOut:h,inputMint:a,outputMint:r,swapMode:n,notEnoughLiquidity:_,priceImpact:S,depositAndNetworkFee:g.default.add(v,M),platformFee:{amount:w,token:a,pct:+e.numerator.toString()/100}}})({route:t,amountOut:e,slippage:r,inputMint:o,outputMint:i,swapMode:n,feeBps:a,userTokensMap:u})));return p.filter(s).sort(((t,e)=>g.default.lessThanOrEqual(e.amountIn,t.amountIn)?1:-1))}return[pt]};function lt(t){const e=new Map;return t.forEach((t=>{var n;(n=t.reserveTokenMints).reduce(((t,e)=>(n.forEach((n=>{e!==n&&t.push([e,n])})),t)),[]).forEach((([n,o])=>{!function(t,e,n,o){let i=o.get(t);i||(i=new Map([[e,[]]]),o.set(t,i));let a=i.get(e);a||(a=[],i.set(e,a)),a.push({inputToken:t,outputToken:e,amm:n})}(n,o,t,e)}))})),e}function dt({inputMint:t,outputMint:e,tokenRouteSegments:n,intermediateTokens:o}){const i=[],a=n.get(t)||new Map;(a.get(e)||[]).forEach((t=>{i.push([t])}));const r=n.get(e)||new Map;for(const[t,e]of a.entries()){if(o&&!o.includes(t))continue;const n=r.get(t)||[];for(const t of e)for(const e of n)i.push([t,{amm:e.amm,inputToken:e.outputToken,outputToken:e.inputToken}])}return i}const mt={feeBps:0,feeAccountId:"",feeAccountTokens:new Map};w.default.config({precision:36,rounding:8,toExpNeg:-40,toExpPos:40});const ft={finality:"optimistic"},gt=new Map;class ht extends r.JsonRpcProvider{static from(t){const e="string"==typeof t?t:t.rpcAddr;return gt.has(e)||gt.set(e,new ht({url:e})),gt.get(e)}static fromNetwork(t){switch(t){case"mainnet":return It;case"testnet":return wt;default:throw new TypeError("Invalid network only mainnet or testnet")}}async viewCode(t,e){return Buffer.from(await this.viewCodeRaw(t,e),"base64")}async viewCodeRaw(t,e=ft){const{code_base64:n}=await this.query({request_type:"view_code",account_id:t,...e});return n}async viewAccount(t,e=ft){return this.query({request_type:"view_account",account_id:t,...e})}async accountExists(t,e){try{return await this.viewAccount(t,e),!0}catch{return!1}}async viewAccessKey(t,e,n=ft){return this.query({request_type:"view_access_key",account_id:t,public_key:"string"==typeof e?e:e.toString(),...n})}async protocolConfig(t=ft){return this.experimental_protocolConfig(t)}async accountBalance(t,e){const n=await this.protocolConfig(e),o=await this.viewAccount(t,e),i=u.NEAR.from(n.runtime_config.storage_amount_per_byte),a=u.NEAR.from(o.storage_usage).mul(i),r=u.NEAR.from(o.locked),s=u.NEAR.from(o.amount).add(r),p=s.sub(r.max(a));return{total:s,stateStaked:a,staked:r,available:p}}async viewCall(t,e,n,o){const i=s.stringifyJsonOrBytes(n);return this.viewCallRaw(t,e,i.toString("base64"),o)}async viewCallRaw(t,e,n,o=ft){return this.query({request_type:"call_function",account_id:t,method_name:e,args_base64:n,...o})}async viewState(t,e,n){return(await this.viewStateRaw(t,e,n)).map((({key:t,value:e})=>({key:Buffer.from(t,"base64"),value:Buffer.from(e,"base64")})))}async viewStateRaw(t,e,n){const{values:o}=await this.query({request_type:"view_state",...null!=n?n:{finality:"optimistic"},account_id:t,prefix_base64:Buffer.from(e).toString("base64")});return o}}const wt=new ht({url:"https://rpc.testnet.near.org"}),It=new ht({url:"https://rpc.mainnet.near.org"});class yt{constructor(t,e,n,o,i,a,r,u,s){this.wrapNear=void 0,this.near=void 0,this.provider=void 0,this.tokenMap=void 0,this.availableTokens=void 0,this.tokenRouteSegments=void 0,this.platformFeeAndAccounts=void 0,this.routeCacheDuration=void 0,this.intermediateTokens=void 0,this.user=void 0,this.routeCache=void 0,this.userTokensMapCache=void 0,this.wrapNear=s,this.provider=e,this.near=t,this.tokenMap=n,this.availableTokens=o,this.tokenRouteSegments=i,this.platformFeeAndAccounts=a,this.routeCacheDuration=r,this.intermediateTokens=u,this.user=null,this.routeCache=new Map,this.userTokensMapCache=new Map}static async load({provider:e=It,user:n,privateKey:i,platformFeeAndAccounts:a=mt,routeCacheDuration:r=0,wrapNear:u=!0}){const s=new o.keyStores.InMemoryKeyStore;if(n&&i){const t=o.KeyPair.fromString(i);await s.setKey("mainnet",n,t)}const p=await o.connect({networkId:"mainnet",nodeUrl:"https://rpc.mainnet.near.org",keyStore:s,headers:{}}),[c,l]=await yt.fetchTokenRouteSegments(e),d=await(new t.TokenListProvider).resolve().then((t=>t.filterByNearEnv("mainnet").getList().reduce(((t,e)=>(t.set(e.address,e),t)),new Map))),m=yt.getIntermediateTokens(),f=new yt(p,e,d,l,c,a,r,m,u);return n&&f.setUserPublicKey(n),f}static async fetchTokenRouteSegments(t){const e=await at(t);return[lt(e),Array.from(new Set(e.flatMap((t=>t.reserveTokenMints))))]}static getIntermediateTokens(){return["wrap.near","usn","dac17f958d2ee523a2206206994597c13d831ec7.factory.bridge.near","a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near","token.pembrock.near"]}setUserPublicKey(t){this.user=t}async loadAndSavePlatformFeeTokenData(t){try{const{storageBalance:e}=await V({provider:this.provider,tokenId:t,tokenOwnerId:this.platformFeeAndAccounts.feeAccountId});return this.platformFeeAndAccounts.feeAccountTokens.set(t,e),e}catch(t){return console.warn("Unable to load token data for platform fee account",t),null}}async getPlatformFeeBpsForToken(t){return(this.platformFeeAndAccounts.feeAccountTokens.has(t)?this.platformFeeAndAccounts.feeAccountTokens.get(t):await this.loadAndSavePlatformFeeTokenData(t))?this.platformFeeAndAccounts.feeBps:0}async computeRoutes({inputMint:t,outputMint:e,amount:n,slippage:o=0,forceFetch:i=!1,swapMode:a=exports.SwapMode.ExactIn,simpleRoutesOnly:r=!1}){const u=await this.getPlatformFeeBpsForToken(e),s=H.fromFeeBpsNumber(u),p=(new Date).getTime(),c=[t,e,r?"simple":"complex"].sort(((t,e)=>t.localeCompare(e))).join(""),l=this.routeCache.get(c),d=dt({inputMint:t,outputMint:e,tokenRouteSegments:this.tokenRouteSegments,intermediateTokens:this.intermediateTokens}).filter((t=>{if(r){const e=1===t.length,n=st(t.map((t=>t.amm)));return!t.some((t=>t.amm instanceof nt))&&(e||n)}return!0}));let m=!1;if(-1===this.routeCacheDuration)m=!1;else if(0===this.routeCacheDuration)m=!0;else if(l){const{fetchTimestamp:t}=l;p-t>this.routeCacheDuration&&(m=!0)}else m=!0;(i||m)&&(await rt(this.provider,d),this.routeCache.set(c,{fetchTimestamp:(new Date).getTime()}));try{const r=this.userTokensMapCache.get(c),u=r||new Map;if(null!==this.user&&!r){const t=[];d.forEach((e=>e.forEach((({amm:e})=>e.reserveTokenMints.forEach((e=>t.push(e))))))),(await Promise.all(t.map((t=>V({provider:this.provider,tokenId:t,tokenOwnerId:this.user}))))).forEach((({tokenId:t,existing:e,storageBalance:n})=>u.set(t,{existing:e,data:n}))),this.userTokensMapCache.set(c,u)}const l=H.fromSlippageNumber(o);return{routesInfos:ct({routes:d,inputMint:t,outputMint:e,amount:n,userTokensMap:u,slippage:l,feeBps:s,swapMode:a}),cached:!(i||m)}}catch(t){throw t}finally{this.routeCache.forEach((({fetchTimestamp:t},e)=>{t-p>this.routeCacheDuration&&this.routeCache.delete(e)}))}}async buildTransactions({route:t}){const e=[],n=st(t.steps.map((t=>t.amm))),i=n?[[]]:t.steps.map((()=>[])),a=await this.getPlatformFeeBpsForToken(t.outputMint),r=H.fromFeeBpsNumber(a);if(!this.user)throw new Error("No user provided");const u=this.user,s=new o.Account(this.near.connection,this.user),p=new Set;if(this.wrapNear&&"wrap.near"===t.inputMint){console.log("Wrap near: ",t.amountIn.toString());const n=await(async(t,e)=>({receiverId:"wrap.near",signerId:t.accountId,actions:await Y(t,e)}))(s,t.amountIn);n.actions.length>0&&(e.push(n),i[0].push(n),p.add("wrap.near"))}t.steps.forEach((t=>p.add(t.outputMint)));const c=[...p.values()],l=(await Promise.all(c.map((t=>X(this.provider,t,u))))).filter((t=>!!t));if(e.push(...l),i[0].push(...l),n){const n=t.steps[0].amm,o=await n.createSwapRouteInstructions({provider:this.provider,user:this.user,swapRoute:t});e.push(...o),i[i.length-1].push(...o)}else{let n=0;for(let o of t.steps){const t=await o.amm.createSwapInstructions({provider:this.provider,user:this.user,swapStep:o});e.push(...t),i[n].push(...t),n++}}let d=t.minAmountOut;if(0!==a&&this.platformFeeAndAccounts.feeAccountId){const n=t.swapMode===exports.SwapMode.ExactIn?t.outputMint:t.inputMint,o=t.swapMode===exports.SwapMode.ExactIn?t.amountOut:t.amountIn,i=r.getFrom(g.default.BigInt(o));e.push((({tokenId:t,accountFrom:e,accountTo:n,amount:o})=>({receiverId:t,signerId:e,actions:[{type:"FunctionCall",params:{methodName:"ft_transfer",args:{receiver_id:n,amount:o.toString(),memo:"perk"},gas:k,deposit:"1"}}]}))({tokenId:n,accountFrom:this.user,accountTo:this.platformFeeAndAccounts.feeAccountId,amount:i})),t.swapMode===exports.SwapMode.ExactIn&&(d=g.default.subtract(d,i))}if(this.wrapNear&&"wrap.near"===t.outputMint){const t=await tt(u,d);e.push(t),i[i.length-1].push(t)}return c.length>0&&this.userTokensMapCache.clear(),{transactions:e,transactionsBySteps:i}}async exchange({route:t}){const{transactions:e}=await this.buildTransactions({route:t});if(!this.user)throw new Error("No user provided");const o=await this.near.account(this.user),i=[];for(const t of e)for(const e of t.actions){if("FunctionCall"!==e.type)throw new Error("Non function call in exchange");const a=await o.functionCall({contractId:t.receiverId,methodName:e.params.methodName,args:e.params.args,gas:new n.BN(e.params.gas),attachedDeposit:new n.BN(e.params.deposit)});i.push(a)}return i}}Object.defineProperty(exports,"Connection",{enumerable:!0,get:function(){return o.Connection}}),Object.defineProperty(exports,"KeyPair",{enumerable:!0,get:function(){return o.KeyPair}}),Object.defineProperty(exports,"JSONRpc",{enumerable:!0,get:function(){return r.JsonRpcProvider}}),Object.defineProperty(exports,"AccessKey",{enumerable:!0,get:function(){return s.AccessKey}}),Object.defineProperty(exports,"Action",{enumerable:!0,get:function(){return s.Action}}),Object.defineProperty(exports,"addKey",{enumerable:!0,get:function(){return s.addKey}}),Object.defineProperty(exports,"createAccount",{enumerable:!0,get:function(){return s.createAccount}}),Object.defineProperty(exports,"deleteAccount",{enumerable:!0,get:function(){return s.deleteAccount}}),Object.defineProperty(exports,"deleteKey",{enumerable:!0,get:function(){return s.deleteKey}}),Object.defineProperty(exports,"deployContract",{enumerable:!0,get:function(){return s.deployContract}}),Object.defineProperty(exports,"fullAccessKey",{enumerable:!0,get:function(){return s.fullAccessKey}}),Object.defineProperty(exports,"functionCall",{enumerable:!0,get:function(){return s.functionCall}}),Object.defineProperty(exports,"stake",{enumerable:!0,get:function(){return s.stake}}),Object.defineProperty(exports,"transfer",{enumerable:!0,get:function(){return s.transfer}}),Object.defineProperty(exports,"ServerError",{enumerable:!0,get:function(){return p.ServerError}}),Object.defineProperty(exports,"KeyPairEd25519",{enumerable:!0,get:function(){return c.KeyPairEd25519}}),Object.defineProperty(exports,"PublicKey",{enumerable:!0,get:function(){return c.PublicKey}}),Object.defineProperty(exports,"KeyStore",{enumerable:!0,get:function(){return l.KeyStore}}),Object.defineProperty(exports,"DEFAULT_FUNCTION_CALL_GAS",{enumerable:!0,get:function(){return m.DEFAULT_FUNCTION_CALL_GAS}}),exports.BN=class extends h.default{toJSON(){return this.toString(10)}},exports.Jumbo=$,exports.MAINNET_RPC_ADDR="https://rpc.mainnet.near.org",exports.NO_PLATFORM_FEE=mt,exports.PerkAggregator=yt,exports.PerkLiquidity=W,exports.RefFinance=G,exports.SPIN_CONTRACT_ADDRESS="spot.spin-fi.near",exports.SpinFinanceMarket=nt,exports.TESTNET_RPC_ADDR="https://rpc.testnet.near.org",exports.TonicFoundationMarket=it,exports.computeRoutes=dt,exports.getAllAmms=at,exports.getSwapRoutes=ct,exports.getTokenRouteSegments=lt,exports.updateRoutesPools=rt,Object.keys(d).forEach((function(t){"default"===t||exports.hasOwnProperty(t)||Object.defineProperty(exports,t,{enumerable:!0,get:function(){return d[t]}})}));
//# sourceMappingURL=perk-swap-core.cjs.production.min.js.map