diff --git a/dist/index.d.ts b/dist/index.d.ts index 156a96b2..14c5123d 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,5 +1,8 @@ +import SwapQuoteError from "./util/error/SwapQuoteError"; export type { InitiatorSigner, SignerTransaction, SupportedNetwork } from "./util/commonTypes"; export { BASE_MINIMUM_BALANCE, MINIMUM_BALANCE_REQUIRED_PER_ASSET, MINIMUM_BALANCE_REQUIRED_PER_APP, MINIMUM_BALANCE_REQUIRED_PER_BYTE_SCHEMA, MINIMUM_BALANCE_REQUIRED_PER_INT_SCHEMA_VALUE, MINIMUM_ADD_LIQUIDITY_AMOUNT } from "./util/constant"; +export * from "./swap/v2/router"; +export * from "./swap/common/utils"; export { applySlippageToAmount, ASSET_OPT_IN_PROCESS_TXN_COUNT, convertFromBaseUnits, convertToBaseUnits, sendAndWaitRawTransaction, getTxnGroupID, sumUpTxnFees } from "./util/util"; export { generateOptIntoAssetTxns } from "./util/asset/assetUtils"; export type { AccountAsset, TinymanAnalyticsApiAsset, IndexerAssetInformation } from "./util/asset/assetModels"; @@ -26,10 +29,13 @@ export type { V2RemoveLiquidityQuote, V2SingleAssetRemoveLiquidityQuote, V2Remov export { V1_1_REMOVE_LIQUIDITY_TXN_COUNT } from "./remove-liquidity/v1_1/constants"; export { V2_REMOVE_LIQUIDITY_APP_CALL_INNER_TXN_COUNT } from "./remove-liquidity/v2/constants"; export { RemoveLiquidity } from "./remove-liquidity"; -export type { SwapQuote, SwapQuoteWithPool, V1SwapExecution, V2SwapExecution } from "./swap/types"; -export { getSwapTotalFee } from "./swap/utils"; +export type { SwapQuote, V1SwapExecution, V2SwapExecution, DirectSwapQuote, SwapRoute, GenerateSwapTxnsParams } from "./swap/types"; +export * from "./swap/v2/util"; export { SwapType } from "./swap/constants"; export { Swap } from "./swap"; +export { SwapQuoteType } from "./swap/types"; +export { SwapQuoteError }; +export { SwapQuoteErrorType } from "./util/error/SwapQuoteError"; export { redeemExcessAsset, redeemAllExcessAsset, generateRedeemTxns, REDEEM_PROCESS_TXN_COUNT } from "./redeem"; export { prepareCommitTransactions, getStakingAppID } from "./stake"; export { tinymanJSSDKConfig } from "./config"; diff --git a/dist/index.js b/dist/index.js index 56528f5c..b29614ad 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -"use strict";var t=require("algosdk"),e=require("base64-js"),n=Uint8Array.from([1]),r=1e5,s=1e5,a=1e5,o=1e5,i=1e5,u=5e4,c=28500,p=1e3,l=1e3;function d(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function f(t){for(var e=1;e=0;--s){var a=this.tryEntries[s],o=a.completion;if("root"===a.tryLoc)return r("end");if(a.tryLoc<=this.prev){var i=n.call(a,"catchLoc"),u=n.call(a,"finallyLoc");if(i&&u){if(this.prev=0;--r){var s=this.tryEntries[r];if(s.tryLoc<=this.prev&&n.call(s,"finallyLoc")&&this.prev=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),D(n),l}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var r=n.completion;if("throw"===r.type){var s=r.arg;D(n)}return s}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:E(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=void 0),l}},t}function g(t,e,n,r,s,a,o){try{var i=t[a](o),u=i.value}catch(t){return void n(t)}i.done?e(u):Promise.resolve(u).then(r,s)}function I(t){return function(){var e=this,n=arguments;return new Promise((function(r,s){var a=t.apply(e,n);function o(t){g(a,r,s,o,i,"next",t)}function i(t){g(a,r,s,o,i,"throw",t)}o(void 0)}))}}function A(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function x(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,i=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return o=t.done,t},e:function(t){i=!0,a=t},f:function(){try{o||null==n.return||n.return()}finally{if(i)throw a}}}}function F(t){var e=function(t,e){if("object"!=typeof t||null===t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var r=n.call(t,e||"default");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"==typeof e?e:String(e)}var B="- would result negative",R="logic eval error:",M="exceeds schema integer count",C=/transaction \w+:/,X=function(t){v(n,b(Error));var e=S(n);function n(t,r){var s;A(this,n);for(var a=arguments.length,o=new Array(a>2?a-2:0),i=2;i1||e<0)throw new Error("Invalid slippage value. Must be between 0 and 1, got ".concat(e));var r;try{var s="negative"===t?1-e:1+e;r=BigInt(Math.floor(Number(n)*s))}catch(t){throw new Error(t.message)}return r}function Z(t,e){var n=Number(t);return $({decimalPlaces:n},Math.pow(10,-n)*Number(e))}function $(t,e){var n=t.decimalPlaces,r=void 0===n?0:n;if(r>0){var s=O(et(e),2),a=s[0],o=s[1],i=O(et(Math.round(Number(tt(a,o+r)))),2),u=i[0],c=i[1];return Number(tt(u,c-r))}return Math.round(e)}function tt(t,e){return t+(e<0?"e".concat(e):"e+".concat(e))}function et(t){if(t.toString().includes("e")){var e=t.toString().split("e");return[parseFloat(e[0]),parseFloat(e[1])]}return[t,0]}function nt(t,e){return rt.apply(this,arguments)}function rt(){return(rt=I(m().mark((function t(e,n){var r,s,a,o,i,u,c,p;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:t.prev=0,r=[],s=L(n),t.prev=3,s.s();case 5:if((a=s.n()).done){t.next=18;break}return o=a.value,t.next=9,e.sendRawTransaction(o).do();case 9:return i=t.sent,u=i.txId,t.next=13,Y(e,u);case 13:c=t.sent,p=c["confirmed-round"],r.push({confirmedRound:p,txnID:u});case 16:t.next=5;break;case 18:t.next=23;break;case 20:t.prev=20,t.t0=t.catch(3),s.e(t.t0);case 23:return t.prev=23,s.f(),t.finish(23);case 26:return t.abrupt("return",r);case 29:throw t.prev=29,t.t1=t.catch(0),new X(t.t1,"We encountered an error while processing this transaction. Try again later.");case 32:case"end":return t.stop()}}),t,null,[[0,29],[3,20,23,26]])})))).apply(this,arguments)}function st(t){return t.reduce((function(t,e){return t+e.txn.fee}),0)}function at(t){return(e=t[0].txn.group)?Buffer.from(e).toString("base64"):"";var e}function ot(t){for(var e=[];;){var n=127&t;if(!(t>>=7)){e.push(n);break}e.push(128|n)}return e}function it(t){return(new TextEncoder).encode(t)}var ut=0,ct={id:"".concat(ut),name:"Algorand",unit_name:"ALGO",decimals:6,url:"https://algorand.org",is_liquidity_token:!1,total_amount:"6615503326932151",clawback_address:""},pt={V1:"TM1POOL",V1_1:"TMPOOL11",V2:"TMPOOL2"};function lt(){return(lt=I(m().mark((function e(n){var r,s,a,o,i;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.assetID,a=n.initiatorAddr,e.prev=1,e.next=4,r.getTransactionParams().do();case 4:return o=e.sent,i=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:a,to:a,assetIndex:s,amount:0,suggestedParams:o}),e.abrupt("return",[{txn:i,signers:[a]}]);case 9:throw e.prev=9,e.t0=e.catch(1),new X(e.t0,"We encountered something unexpected while opting into this asset. Try again later.");case 12:case"end":return e.stop()}}),e,null,[[1,9]])})))).apply(this,arguments)}function dt(t,e){var n=Number(t.id),r=Number(e.id);return n>r?[f(f({},t),{},{id:n}),f(f({},e),{},{id:r})]:[f(f({},e),{},{id:r}),f(f({},t),{},{id:n})]}function ft(t,e){var n=[t,e];return[Math.max.apply(Math,n),Math.min.apply(Math,n)]}function mt(t){return Number(t)===ut}var gt,It={V1_1:"v1_1",V2:"v2"},At={type:"logicsig",logic:{bytecode:"BCAIAQCBgICAgICAgPABgICAgICAgIDwAQMEBQYlJA1EMQkyAxJEMRUyAxJEMSAyAxJEMgQiDUQzAQAxABJEMwEQIQcSRDMBGIGCgICAgICAgPABEkQzARkiEjMBGyEEEhA3ARoAgAlib290c3RyYXASEEAAXDMBGSMSRDMBG4ECEjcBGgCABHN3YXASEEACOzMBGyISRDcBGgCABG1pbnQSQAE7NwEaAIAEYnVybhJAAZg3ARoAgAZyZWRlZW0SQAJbNwEaAIAEZmVlcxJAAnkAIQYhBSQjEk0yBBJENwEaARclEjcBGgIXJBIQRDMCADEAEkQzAhAhBBJEMwIhIxJEMwIiIxwSRDMCIyEHEkQzAiQjEkQzAiWACFRNUE9PTDExEkQzAiZRAA+AD1RpbnltYW5Qb29sMS4xIBJEMwIngBNodHRwczovL3RpbnltYW4ub3JnEkQzAikyAxJEMwIqMgMSRDMCKzIDEkQzAiwyAxJEMwMAMQASRDMDECEFEkQzAxElEkQzAxQxABJEMwMSIxJEJCMTQAAQMwEBMwIBCDMDAQg1AUIBsTMEADEAEkQzBBAhBRJEMwQRJBJEMwQUMQASRDMEEiMSRDMBATMCAQgzAwEIMwQBCDUBQgF8MgQhBhJENwEcATEAE0Q3ARwBMwQUEkQzAgAxABNEMwIUMQASRDMDADMCABJEMwIRJRJEMwMUMwMHMwMQIhJNMQASRDMDESMzAxAiEk0kEkQzBAAxABJEMwQUMwIAEkQzAQEzBAEINQFCAREyBCEGEkQ3ARwBMQATRDcBHAEzAhQSRDMDFDMDBzMDECISTTcBHAESRDMCADEAEkQzAhQzBAASRDMCESUSRDMDADEAEkQzAxQzAwczAxAiEk0zBAASRDMDESMzAxAiEk0kEkQzBAAxABNEMwQUMQASRDMBATMCAQgzAwEINQFCAJAyBCEFEkQ3ARwBMQATRDMCADcBHAESRDMCADEAE0QzAwAxABJEMwIUMwIHMwIQIhJNMQASRDMDFDMDBzMDECISTTMCABJEMwEBMwMBCDUBQgA+MgQhBBJENwEcATEAE0QzAhQzAgczAhAiEk03ARwBEkQzAQEzAgEINQFCABIyBCEEEkQzAQEzAgEINQFCAAAzAAAxABNEMwAHMQASRDMACDQBD0M=",address:"ABUKAXTANWR6K6ZYV75DWJEPVWWOU6SFUVRI6QHO44E4SIDLHBTD2CZ64A",size:881,variables:[{name:"TMPL_ASSET_ID_1",type:"int",index:15,length:10},{name:"TMPL_ASSET_ID_2",type:"int",index:5,length:10},{name:"TMPL_VALIDATOR_APP_ID",type:"int",index:74,length:10}],source:"https://github.com/tinymanorg/tinyman-contracts-v1/tree/dc9ab40c58b85c15d58f63a1507e18be76720dbb/contracts/pool_logicsig.teal.tmpl"},name:"pool_logicsig"},xt={type:"app",global_state_schema:{num_uints:0,num_byte_slices:0},local_state_schema:{num_uints:16,num_byte_slices:0},name:"validator_app"},ht=new(function(){function t(){A(this,t),this.clientName="tinyman-js-sdk"}return h(t,[{key:"getClientName",value:function(){return this.clientName}},{key:"setClientName",value:function(t){this.clientName=t}},{key:"getAppCallTxnNoteWithClientName",value:function(t){var e=t===It.V1_1?"v1":t;return it("tinyman/".concat(e,':j{"origin":"').concat(this.clientName,'"}'))}}]),t}()),Tt=(T(gt={},It.V1_1,{testnet:62368684,mainnet:552635992}),T(gt,It.V2,{testnet:148607e3,mainnet:1002541853}),gt);function vt(t,e){var n=Tt[e][t];if(!n)throw new Error("No Validator App exists for ".concat(t," network with ").concat(e," contract version"));return n}function yt(){return(yt=I(m().mark((function e(n){var r,s,a,o,i,u;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,a=n.contractVersion,o=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return i=e.sent,u=t.makeApplicationOptInTxnFromObject({from:o,appIndex:vt(s,a),note:ht.getAppCallTxnNoteWithClientName(a),suggestedParams:i}),e.abrupt("return",[{txn:u,signers:[o]}]);case 6:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function _t(){return(_t=I(m().mark((function e(n){var r,s,a,o,i,u;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,a=n.contractVersion,o=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return i=e.sent,u=t.makeApplicationClearStateTxnFromObject({from:o,appIndex:vt(s,a),note:ht.getAppCallTxnNoteWithClientName(a),suggestedParams:i}),e.abrupt("return",[{txn:u,signers:[o]}]);case 6:case"end":return e.stop()}}),e)})))).apply(this,arguments)}var wt=h((function t(e){A(this,t),this.schema={numLocalInts:e.local_state_schema.num_uints,numLocalByteSlices:e.local_state_schema.num_byte_slices,numGlobalInts:e.global_state_schema.num_uints,numGlobalByteSlices:e.global_state_schema.num_byte_slices}})),Dt=new(function(n){v(s,wt);var r=S(s);function s(t,e){var n;return A(this,s),(n=r.call(this,t)).poolLogicSigContractTemplate=e.logic.bytecode,n.templateVariables=e.logic.variables,n}return h(s,[{key:"generateLogicSigAccountForPool",value:function(n){if(n.asset1ID===n.asset2ID)throw new Error("Assets are the same");var r=vt(n.network,It.V1_1),s=O(ft(n.asset1ID,n.asset2ID),2),a=s[0],o=s[1],i=Array.from(e.toByteArray(this.poolLogicSigContractTemplate)),u={asset_id_1:a,asset_id_2:o,validator_app_id:r},c=0;this.templateVariables.sort((function(t,e){return t.index-e.index}));for(var p=0;p2&&void 0!==arguments[2]?arguments[2]:t.IntDecoding.DEFAULT;return new Promise(function(){var t=I(m().mark((function t(s,a){var o;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.prev=0,t.next=3,e.accountInformation(n).setIntDecoding(r).do();case 3:o=t.sent,s(f(f({},o),{},{minimum_required_balance:kt(o)})),t.next=10;break;case 7:t.prev=7,t.t0=t.catch(0),a(new Error(t.t0.message||"Failed to fetch account information"));case 10:case"end":return t.stop()}}),t,null,[[0,7]])})));return function(e,n){return t.apply(this,arguments)}}())}function Pt(t,e){var n=t["apps-local-state"].find((function(t){return t.id===e}));return n?j({stateArray:n["key-value"],shouldDecodeKeys:!0}):null}function kt(t){var e=t["apps-total-schema"];return r+s*(t.assets||[]).length+o*(t["created-apps"]||[]).length+a*(t["apps-local-state"]||[]).length+u*Number(e&&e["num-byte-slice"]||0)+c*Number(e&&e["num-uint"]||0)+i*(t["apps-total-extra-pages"]||0)}var Lt=it("e");function Ft(t){return Bt.apply(this,arguments)}function Bt(){return(Bt=I(m().mark((function n(r){var s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T,v,y,_,w,D;return m().wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return s=r.client,a=r.pool,o=r.accountAddr,n.next=3,s.accountInformation(o).setIntDecoding(t.IntDecoding.BIGINT).do();case 3:i=n.sent,u=i["apps-local-state"]||[],c=0n,p=0n,l=0n,d=a.account.address(),f=L(u),n.prev=10,f.s();case 12:if((g=f.n()).done){n.next=31;break}if((I=g.value).id==a.validatorAppID){n.next=16;break}return n.abrupt("continue",29);case 16:if(A=I["key-value"]){n.next=19;break}return n.abrupt("break",31);case 19:x=j({stateArray:A}),h=e.fromByteArray(V([t.decodeAddress(d).publicKey,Lt,t.encodeUint64(a.asset1ID)])),T=e.fromByteArray(V([t.decodeAddress(d).publicKey,Lt,t.encodeUint64(a.asset2ID)])),v=e.fromByteArray(V([t.decodeAddress(d).publicKey,Lt,t.encodeUint64(a.poolTokenID)])),y=x[h],_=x[T],w=x[v],"bigint"==typeof y&&(c=y),"bigint"==typeof _&&(p=_),"bigint"==typeof w&&(l=w);case 29:n.next=12;break;case 31:n.next=36;break;case 33:n.prev=33,n.t0=n.catch(10),f.e(n.t0);case 36:return n.prev=36,f.f(),n.finish(36);case 39:if(!((D={excessAsset1:c,excessAsset2:p,excessPoolTokens:l}).excessAsset1<0n||D.excessAsset2<0n||D.excessPoolTokens<0n)){n.next=42;break}throw new Error("Invalid account excess: ".concat(D));case 42:return n.abrupt("return",D);case 43:case"end":return n.stop()}}),n,null,[[10,33,36,39]])})))).apply(this,arguments)}function Rt(){return(Rt=I(m().mark((function n(r){var s,a,o,i,u,c,p,l,d,f,g,I,A,x,h;return m().wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return s=r.client,a=r.accountAddr,o=r.validatorAppID,n.next=3,s.accountInformation(a).setIntDecoding(t.IntDecoding.BIGINT).do();case 3:if(i=n.sent,u=i["apps-local-state"]||[],c=u.find((function(t){return t.id==o})),p=[],c&&c["key-value"])for(l=j({stateArray:c["key-value"]}),d=0,f=Object.entries(l);dQt)){n.next=48;break}throw new Error("Issued liquidity value is out of the expected range ([0n, ".concat(Qt,"]): ").concat(P.issuedLiquidity));case 48:return n.abrupt("return",P);case 49:case"end":return n.stop()}}),n,null,[[8,31,34,37]])})))).apply(this,arguments)}function qt(){return qt=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l=arguments;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(n=e.client,r=e.address,s=e.network,!(a=l.length>1&&void 0!==l[1]?l[1]:{})[r]){t.next=4;break}return t.abrupt("return",a[r]);case 4:return t.next=6,Nt(n,r);case 6:return o=t.sent,i=Pt(o,vt(s,It.V1_1)),u=null,i&&(p=o["created-assets"][0],c=p.index,u={asset1ID:i[Xt[It.V1_1].asset1],asset2ID:i[Xt[It.V1_1].asset2],poolTokenID:c},a[r]=u),t.abrupt("return",u);case 11:case"end":return t.stop()}}),t)}))),qt.apply(this,arguments)}var zt=Object.freeze({__proto__:null,getPoolAssets:function(t){return qt.apply(this,arguments)},getPoolInfo:Ut,getPoolReserves:function(t,e){return Wt.apply(this,arguments)}});function Jt(t){return Yt.apply(this,arguments)}function Yt(){return(Yt=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l,d,f;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.network,s=e.asset1ID,a=e.asset2ID,o=Ot(It.V2),i=o.generateLogicSigAccountForPool(e),u=vt(r,It.V2),c=i.address(),p=ft(s,a),t.next=8,Nt(n,c);case 8:return l=t.sent,d=Pt(l,u),f={account:i,validatorAppID:u,asset1ID:p[0],asset2ID:p[1],status:d?Ct.READY:Ct.NOT_CREATED,contractVersion:It.V2},d&&(f.asset1ProtocolFees=BigInt(d[Xt.v2.asset1ProtocolFees]),f.asset2ProtocolFees=BigInt(d[Xt.v2.asset2ProtocolFees]),f.asset1Reserves=BigInt(d[Xt.v2.asset1Reserves]),f.asset2Reserves=BigInt(d[Xt.v2.asset2Reserves]),f.issuedPoolTokens=BigInt(d[Xt.v2.issuedPoolTokens]),f.cumulativePriceUpdateTimeStamp=Number(d[Xt.v2.cumulativePriceUpdateTimeStamp]),f.protocolFeeRatio=Number(d[Xt.v2.protocolFeeRatio]),f.totalFeeShare=BigInt(d[Xt.v2.totalFeeShare]),f.poolTokenID=Number(d[Xt.v2.poolTokenID]),f.asset1ID=Number(d[Xt.v2.asset1]),f.asset2ID=Number(d[Xt.v2.asset2])),t.abrupt("return",f);case 13:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Kt(){return(Kt=I(m().mark((function t(e,n){var r,s,a;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,Nt(e,n.account.address());case 2:return r=t.sent,s=Pt(r,n.validatorAppID),a={asset1:0n,asset2:0n,issuedLiquidity:0n,round:r.round},s&&(a.asset1=BigInt(s[Xt.v2.asset1Reserves]),a.asset2=BigInt(s[Xt.v2.asset2Reserves]),a.issuedLiquidity=BigInt(s[Xt.v2.issuedPoolTokens])),t.abrupt("return",a);case 7:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Ht(){return(Ht=I(m().mark((function t(e){var n,r,s,a,o,i;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.address,s=e.network,t.next=3,Nt(n,r);case 3:return a=t.sent,o=Pt(a,vt(s,It.V2)),i=null,o&&(i={asset1ID:o[Xt[It.V2].asset1],asset2ID:o[Xt[It.V2].asset2],poolTokenID:o[Xt[It.V2].poolTokenID]}),t.abrupt("return",i);case 8:case"end":return t.stop()}}),t)})))).apply(this,arguments)}var Zt=Object.freeze({__proto__:null,getPoolAssets:function(t){return Ht.apply(this,arguments)},getPoolInfo:Jt,getPoolReserves:function(t,e){return Kt.apply(this,arguments)}});function $t(t){return Boolean(t&&!(t.asset1+t.asset2))}var te,ee=Object.freeze({__proto__:null,getPoolPairRatio:function(t,e){var n=$t(e),r=null;return e&&!n&&e.asset1&&e.asset2&&"number"==typeof t.asset2&&"number"==typeof t.asset1&&(r=Z(t.asset1,e.asset1)/Z(t.asset2,e.asset2)),r},getPoolShare:function(t,e){var n=Number(e)/Number(t);return Number.isFinite(n)||(n=0),n},getPoolsForPair:function(t){return Promise.all([Ut(t),Jt(t)])},isPoolEmpty:$t,isPoolNotCreated:function(t){return(null==t?void 0:t.status)===Ct.NOT_CREATED},isPoolReady:function(t){return(null==t?void 0:t.status)===Ct.READY}}),ne=f((T(te={},It.V1_1,f(f({},zt),ee)),T(te,It.V2,f(f({},Zt),ee)),te),ee),re=function(t){return t[t.FUNDING_TXN=0]="FUNDING_TXN",t[t.VALIDATOR_APP_CALL=1]="VALIDATOR_APP_CALL",t[t.POOL_TOKEN_CREATE=2]="POOL_TOKEN_CREATE",t[t.ASSET1_OPT_IN=3]="ASSET1_OPT_IN",t[t.ASSET2_OPT_IN=4]="ASSET2_OPT_IN",t}({}),se={ASA_ALGO:96e4,ASA_ASA:859e3};function ae(){return(ae=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T,v,y,_,w,D,b,E,S;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,a=n.asset_1,o=n.asset_2,i=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return u=e.sent,c=dt(a,o),p=O(c,2),l=p[0],d=l.id,f=l.unit_name,g=p[1],I=g.id,A=g.unit_name,x=mt(I),h=vt(s,It.V1_1),T=Dt.generateLogicSigAccountForPool({network:s,asset1ID:d,asset2ID:I}),v=T.address(),y=t.makeApplicationOptInTxnFromObject({from:v,appIndex:h,note:ht.getAppCallTxnNoteWithClientName(It.V1_1),appArgs:[it("bootstrap"),t.encodeUint64(d),t.encodeUint64(I)],foreignAssets:x?[d]:[I],suggestedParams:u}),_=t.makeAssetCreateTxnWithSuggestedParamsFromObject({from:v,total:0xffffffffffffffffn,decimals:6,defaultFrozen:!1,unitName:pt.V1_1,assetName:"TinymanPool1.1 ".concat(f,"-").concat(A),assetURL:"https://tinyman.org",suggestedParams:u}),w=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:v,to:v,assetIndex:d,amount:0,suggestedParams:u}),D=t.makePaymentTxnWithSuggestedParamsFromObject({from:i,to:v,amount:oe(x),suggestedParams:u}),(b=[])[re.FUNDING_TXN]=D,b[re.VALIDATOR_APP_CALL]=y,b[re.POOL_TOKEN_CREATE]=_,b[re.ASSET1_OPT_IN]=w,x||(b[re.ASSET2_OPT_IN]=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:v,to:v,assetIndex:I,amount:0,suggestedParams:u})),E=t.assignGroupID(b),S=[{txn:E[re.FUNDING_TXN],signers:[i]},{txn:E[re.VALIDATOR_APP_CALL],signers:[v]},{txn:E[re.POOL_TOKEN_CREATE],signers:[v]},{txn:E[re.ASSET1_OPT_IN],signers:[v]}],E[re.ASSET2_OPT_IN]&&S.push({txn:E[re.ASSET2_OPT_IN],signers:[v]}),e.abrupt("return",S);case 23:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function oe(t){return t?se.ASA_ALGO:se.ASA_ASA}function ie(){return(ie=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A,x;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.txGroup,s=n.network,a=n.initiatorSigner,o=n.asset1ID,i=n.asset2ID,e.next=3,a([r]);case 3:return u=e.sent,c=O(u,1),p=c[0],l=ft(o,i),d=O(l,2),f=d[0],g=d[1],I=Dt.generateLogicSigAccountForPool({network:s,asset1ID:f,asset2ID:g}),A=[],x=r.map((function(e,n){if(n===re.FUNDING_TXN)return A.push(e.txn.txID().toString()),p;var r=t.signLogicSigTransactionObject(e.txn,I),s=r.txID,a=r.blob;return A.push(s),a})),e.abrupt("return",{signedTxns:x,txnIDs:A});case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function ue(t){return ce.apply(this,arguments)}function ce(){return(ce=I(m().mark((function t(e){var n,r,s,a,o;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.signedTxns,s=e.txnIDs,t.prev=1,t.next=4,n.sendRawTransaction(r).do();case 4:return t.next=6,Y(n,s[re.POOL_TOKEN_CREATE]);case 6:if(a=t.sent,"number"==typeof(o=a["asset-index"])){t.next=10;break}throw new Error("Generated ID is not valid: got ".concat(o));case 10:return t.abrupt("return",{poolTokenID:o});case 13:throw t.prev=13,t.t0=t.catch(1),new X(t.t0,"We encountered something unexpected while bootstraping the pool. Try again later.");case 16:case"end":return t.stop()}}),t,null,[[1,13]])})))).apply(this,arguments)}function pe(){return(pe=I(m().mark((function t(e){var n,r,s,a,o,i,u;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.network,s=e.pool,a=s.asset1ID,o=s.asset2ID,i=e.signedTxns,u=e.txnIDs,t.next=3,ue({client:n,signedTxns:i,txnIDs:u});case 3:return t.abrupt("return",ne.v1_1.getPoolInfo({client:n,network:r,asset1ID:a,asset2ID:o}));case 4:case"end":return t.stop()}}),t)})))).apply(this,arguments)}var le={generateTxns:function(t){return ae.apply(this,arguments)},signTxns:function(t){return ie.apply(this,arguments)},execute:function(t){return pe.apply(this,arguments)},getBootstrapFundingTxnAmount:oe};var de=function(t){return t[t.FUNDING_TXN=0]="FUNDING_TXN",t[t.VALIDATOR_APP_CALL=1]="VALIDATOR_APP_CALL",t}({}),fe={ASA_ALGO:5,ASA_ASA:6};function me(t,e){return ge.apply(this,arguments)}function ge(){return(ge=I(m().mark((function e(n,r){var s,a,o;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!(a=null===(s=r.find((function(t){return"appl"===t.txn.type})))||void 0===s?void 0:s.txn.txID())){e.next=7;break}return e.next=4,t.waitForConfirmation(n,a,l);case 4:e.t0=e.sent,e.next=8;break;case 7:e.t0=void 0;case 8:return o=e.t0,e.abrupt("return",o);case 10:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Ie(t,e){return Ae.apply(this,arguments)}function Ae(){return(Ae=I(m().mark((function t(e,n){var r;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,me(e,n);case 2:return r=t.sent,t.abrupt("return",null==r?void 0:r["inner-txns"]);case 4:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function xe(t,e){return he.apply(this,arguments)}function he(){return(he=I(m().mark((function e(n,r){var s;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,Ie(n,r);case 2:return s=e.sent,e.abrupt("return",null==s?void 0:s.reduce((function(e,n){var r=e,s=n.txn.txn;return s.type===t.TransactionType.axfer?r.push({id:s.xaid,amount:s.aamt}):s.type===t.TransactionType.pay&&r.push({id:ut,amount:s.amt}),r}),[]));case 4:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Te(){return(Te=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T,v,y,_;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,a=n.asset_1,o=n.asset_2,i=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return u=e.sent,c=vt(s,It.V2),p=t.getApplicationAddress(c),l=dt(a,o),d=O(l,2),f=d[0].id,g=d[1].id,e.next=9,ne.v2.getPoolInfo({client:r,network:s,asset1ID:f,asset2ID:g});case 9:if(e.sent.status!==Ct.READY){e.next=12;break}throw new Error("Pool for ".concat(a.unit_name,"-").concat(o.unit_name," already exists"));case 12:return I=St.generateLogicSigAccountForPool({network:s,asset1ID:f,asset2ID:g}),A=I.address(),x=mt(g),(h=t.makeApplicationOptInTxnFromObject({from:A,appIndex:c,appArgs:[it("bootstrap")],note:ht.getAppCallTxnNoteWithClientName(It.V2),foreignAssets:[f,g],rekeyTo:p,suggestedParams:u})).fee=ye(x),T=t.makePaymentTxnWithSuggestedParamsFromObject({from:i,to:A,amount:ve(x),suggestedParams:u}),(v=[])[de.FUNDING_TXN]=T,v[de.VALIDATOR_APP_CALL]=h,y=t.assignGroupID(v),(_=[])[de.FUNDING_TXN]={txn:y[de.FUNDING_TXN],signers:[i]},_[de.VALIDATOR_APP_CALL]={txn:y[de.VALIDATOR_APP_CALL],signers:[A]},e.abrupt("return",_);case 26:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function ve(t){return function(t,e){var n=Ot(t).schema,o=n.numLocalInts,i=n.numLocalByteSlices,p=r+s+s+a+c*o+u*i;return e||(p+=s),p}(It.V2,t)+ye(t)+s}function ye(e){return((e?fe.ASA_ALGO:fe.ASA_ASA)+1)*t.ALGORAND_MIN_TX_FEE}function _e(){return(_e=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A,x;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.txGroup,s=n.network,a=n.initiatorSigner,o=n.asset1ID,i=n.asset2ID,e.next=3,a([r]);case 3:return u=e.sent,c=O(u,1),p=c[0],l=ft(o,i),d=O(l,2),f=d[0],g=d[1],I=St.generateLogicSigAccountForPool({network:s,asset1ID:f,asset2ID:g}),A=[],x=r.map((function(e,n){if(n===de.FUNDING_TXN)return A.push(e.txn.txID().toString()),p;var r=t.signLogicSigTransactionObject(e.txn,I),s=r.txID,a=r.blob;return A.push(s),a})),e.abrupt("return",{signedTxns:x,txnIDs:A});case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function we(){return(we=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l,d;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.network,s=e.pool,a=s.asset1ID,o=s.asset2ID,i=e.txGroup,u=e.signedTxns,t.prev=1,t.next=4,n.sendRawTransaction(u).do();case 4:return t.next=6,me(n,i);case 6:if(t.t1=c=t.sent,t.t0=null===t.t1,t.t0){t.next=10;break}t.t0=void 0===c;case 10:if(!t.t0){t.next=14;break}t.t2=void 0,t.next=15;break;case 14:t.t2=null===(p=c["local-state-delta"][0].delta)||void 0===p||null===(l=p.find((function(t){return t.key===btoa(Xt.v2.poolTokenID)})))||void 0===l?void 0:l.value.uint;case 15:if("number"==typeof(d=t.t2)){t.next=18;break}throw new Error("Generated ID is not valid: got ".concat(d));case 18:return t.abrupt("return",ne.v2.getPoolInfo({client:n,network:r,asset1ID:a,asset2ID:o}));case 21:throw t.prev=21,t.t3=t.catch(1),new X(t.t3,"We encountered something unexpected while bootstraping the pool. Try again later.");case 24:case"end":return t.stop()}}),t,null,[[1,21]])})))).apply(this,arguments)}var De,be={generateTxns:function(t){return Te.apply(this,arguments)},signTxns:function(t){return _e.apply(this,arguments)},execute:function(t){return we.apply(this,arguments)},getBootstrapFundingTxnAmount:ve,getTotalCost:function(e){return t.ALGORAND_MIN_TX_FEE+ve(e)}};var Ee,Se,Oe,Ne,Pe=(T(De={},It.V1_1,le),T(De,It.V2,be),T(De,"generateTxns",(function(t){return t.contractVersion===It.V1_1?le.generateTxns(t):be.generateTxns(t)})),T(De,"signTxns",(function(t){return t.contractVersion===It.V1_1?le.signTxns(t):be.signTxns(t)})),T(De,"execute",(function(t){return t.contractVersion===It.V1_1?le.execute(t):be.execute(t)})),T(De,"calculateBootstrapFundingTxnAmount",(function(t){var e=t.contractVersion,n=t.isAlgoPool;return e===It.V1_1?le.getBootstrapFundingTxnAmount(n):be.getBootstrapFundingTxnAmount(n)})),De),ke=function(t){return t[t.FEE_TXN=0]="FEE_TXN",t[t.VALIDATOR_APP_CALL_TXN=1]="VALIDATOR_APP_CALL_TXN",t[t.ASSET1_IN_TXN=2]="ASSET1_IN_TXN",t[t.ASSET2_IN_TXN=3]="ASSET2_IN_TXN",t[t.LIQUDITY_OUT_TXN=4]="LIQUDITY_OUT_TXN",t}({}),Le=5*t.ALGORAND_MIN_TX_FEE,Fe=function(t){return t.SINGLE="single",t.FLEXIBLE="flexible",t.INITIAL="initial",t}({}),Be=(T(Ee={},Fe.FLEXIBLE,{ASSET1_IN_TXN:0,ASSET2_IN_TXN:1,VALIDATOR_APP_CALL_TXN:2}),T(Ee,Fe.SINGLE,{ASSET_IN_TXN:0,VALIDATOR_APP_CALL_TXN:1}),T(Ee,Fe.INITIAL,{ASSET1_IN_TXN:0,ASSET2_IN_TXN:1,VALIDATOR_APP_CALL_TXN:2}),Ee),Re=(T(Se={},Fe.INITIAL,1),T(Se,Fe.SINGLE,2),T(Se,Fe.FLEXIBLE,2),Se),Me=(T(Oe={},Fe.INITIAL,3),T(Oe,Fe.FLEXIBLE,3),T(Oe,Fe.SINGLE,2),Oe);function Ce(t){var e=t.assetIn,n=t.assetOut;return Z(n.decimals,Number(n.amount))/Z(e.decimals,Number(e.amount))}function Xe(t){var e=t.inputSupply,n=t.outputSupply,r=t.assetIn,s=t.assetOut,a=Ce({assetIn:r,assetOut:s}),o=Z(s.decimals,Number(n))/Z(r.decimals,Number(e));return $({decimalPlaces:5},Math.abs(a/o-1))}function je(t){var e,n,r,s=t.reserves,a=t.totalFeeShare,o=t.asset1,i=t.asset2,u=s.asset1*s.asset2,c=s.asset1+BigInt(o.amount),p=s.asset2+BigInt(i.amount),l=c*p,d=BigInt(parseInt(String(Math.sqrt(Number(l*s.issuedLiquidity*s.issuedLiquidity/u))))),f=d-s.issuedLiquidity,m=f*c/d,g=f*p/d,I=BigInt(o.amount)-m,A=BigInt(i.amount)-g;if(I>A){var x=I;r=Qe(x,a),e={id:o.id,amount:x+r,decimals:o.decimals,reserves:s.asset1},n={id:i.id,amount:BigInt(Math.abs(Math.min(Number(A),0))),decimals:i.decimals,reserves:s.asset2},f-=r*d/(c*BigInt(2))}else{var h=A;r=Qe(h,a),e={id:i.id,amount:h+r,decimals:i.decimals,reserves:s.asset2},n={id:o.id,amount:BigInt(Math.abs(Math.min(Number(I),0))),decimals:o.decimals,reserves:s.asset1},f-=r*d/(p*BigInt(2))}return{poolTokenOutAmount:f,internalSwapQuote:{assetIn:e,assetOut:n,swapFees:r,priceImpact:Xe({inputSupply:e.reserves,outputSupply:n.reserves,assetIn:e,assetOut:n})}}}function Ve(t,e){if(!t.amount||!e.amount)throw new Error("Both assets are required for the initial add liquidity");return BigInt(Math.floor(Math.abs(Math.sqrt(Number(t.amount)*Number(e.amount))-jt)))}function Qe(t,e){return t*BigInt(e)/(BigInt(1e4)-BigInt(e))}function Ue(e){return(Re[e]+1)*t.ALGORAND_MIN_TX_FEE}var Ge=it("add_liquidity"),We=(T(Ne={},It.V1_1,[it("mint")]),T(Ne,It.V2,{INITIAL_LIQUIDITY:[it("add_initial_liquidity")],SINGLE_ASSET_MODE:[Ge,it("single")],FLEXIBLE_MODE:[Ge,it("flexible")]}),Ne);function qe(){return(qe=I(m().mark((function e(r){var s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return s=r.client,a=r.network,o=r.poolAddress,i=r.asset1In,u=r.asset2In,c=r.poolTokenOut,p=r.slippage,l=r.initiatorAddr,d=H("negative",p,c.amount),e.next=4,s.getTransactionParams().do();case 4:return f=e.sent,g=t.makeApplicationNoOpTxnFromObject({from:o,appIndex:vt(a,It.V1_1),appArgs:We.v1_1,accounts:[l],note:ht.getAppCallTxnNoteWithClientName(It.V1_1),foreignAssets:u.id==ut?[i.id,c.id]:[i.id,u.id,c.id],suggestedParams:f}),I=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:l,to:o,assetIndex:i.id,amount:i.amount,suggestedParams:f}),A=u.id===ut?t.makePaymentTxnWithSuggestedParamsFromObject({from:l,to:o,amount:u.amount,suggestedParams:f}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:l,to:o,assetIndex:u.id,amount:u.amount,suggestedParams:f}),x=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:o,to:l,assetIndex:c.id,amount:d,suggestedParams:f}),h=t.makePaymentTxnWithSuggestedParamsFromObject({from:l,to:o,amount:g.fee+x.fee,note:n,suggestedParams:f}),T=t.assignGroupID([h,g,I,A,x]),e.abrupt("return",[{txn:T[0],signers:[l]},{txn:T[1],signers:[o]},{txn:T[2],signers:[l]},{txn:T[3],signers:[l]},{txn:T[4],signers:[o]}]);case 12:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function ze(){return(ze=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.pool,s=n.txGroup,a=n.initiatorSigner,o=r.account,e.next=4,a([s]);case 4:return i=e.sent,u=O(i,3),c=u[0],p=u[1],l=u[2],d=s.map((function(e,n){return n===ke.FEE_TXN?c:n===ke.ASSET1_IN_TXN?p:n===ke.ASSET2_IN_TXN?l:t.signLogicSigTransactionObject(e.txn,o).blob})),e.abrupt("return",d);case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Je(){return(Je=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l,d,f,g,I,A,x,h;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.txGroup,a=e.signedTxns,o=e.initiatorAddr,t.prev=1,i=BigInt(s[ke.LIQUDITY_OUT_TXN].txn.amount),t.next=5,Ft({client:n,pool:r,accountAddr:o});case 5:return u=t.sent,t.next=8,nt(n,[a]);case 8:return c=t.sent,p=O(c,1),l=p[0],d=l.confirmedRound,f=l.txnID,g=st(s),I=at(s),t.next=17,Ft({client:n,pool:r,accountAddr:o});case 17:return A=t.sent,(x=A.excessPoolTokens-u.excessPoolTokens)<0n&&(x=0n),t.abrupt("return",{round:d,fees:g,poolTokenID:r.poolTokenID,poolTokenOut:i+x,excessAmount:{excessAmountForAddingLiquidity:x,totalExcessAmount:A.excessPoolTokens},txnID:f,groupID:I});case 23:throw t.prev=23,t.t0=t.catch(1),"SlippageTolerance"===(h=new X(t.t0,"We encountered something unexpected while adding liquidity. Try again later.")).type&&h.setMessage("Adding liquidity failed due to too much slippage in the price. Please adjust the slippage tolerance and try again."),h;case 28:case"end":return t.stop()}}),t,null,[[1,23]])})))).apply(this,arguments)}var Ye=Object.freeze({__proto__:null,execute:function(t){return Je.apply(this,arguments)},generateTxns:function(t){return qe.apply(this,arguments)},getQuote:function(t){var e=t.pool,n=t.reserves,r=t.asset1In,s=t.asset2In;if(0n===n.issuedLiquidity){var a=BigInt(Math.floor(Math.sqrt(Number(r)*Number(s))));if(a<=BigInt(p))throw new Error("Initial liquidity amount is too small. The amount must be greater than ".concat(p,", this quote is for ").concat(a,"."));return{round:n.round,asset1ID:e.asset1ID,asset1In:BigInt(r),asset2ID:e.asset2ID,asset2In:BigInt(s),poolTokenID:e.poolTokenID,poolTokenOut:a-BigInt(p),share:1}}var o=BigInt(r)*n.issuedLiquidity/n.asset1,i=BigInt(s)*n.issuedLiquidity/n.asset2,u=o0&&void 0!==arguments[0]?arguments[0]:"Output amount exceeds available liquidity";return A(this,n),e.call(this,t)}return h(n)}();function En(){return(En=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=n.client,s=n.pool,a=n.swapType,o=n.assetIn,i=n.assetOut,u=n.initiatorAddr,c=n.slippage,p=s.account.address(),(l=[s.asset1ID,s.asset2ID]).includes(o.id)&&l.includes(i.id)&&o.id!==i.id){e.next=5;break}throw new X({pool:s,assetIn:o,assetOut:i},"Input asset (#".concat(o.id,") and output asset (#").concat(i.id,") provided to generate transactions do not belong to the pool ").concat(p,"."));case 5:return e.next=7,r.getTransactionParams().do();case 7:return d=e.sent,f=mt(o.id),g=a===Tn.FixedInput?o.amount:H("positive",c,o.amount),I=a===Tn.FixedOutput?i.amount:H("negative",c,i.amount),A=f?t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:p,amount:g,suggestedParams:d}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:u,to:p,amount:g,assetIndex:o.id,suggestedParams:d}),(x=t.makeApplicationNoOpTxnFromObject({from:u,appIndex:s.validatorAppID,appArgs:[wn,Dn[a],t.encodeUint64(I)],note:ht.getAppCallTxnNoteWithClientName(It.V2),accounts:[p],foreignAssets:[s.asset1ID,s.asset2ID],suggestedParams:d})).fee=Sn(a),(h=[])[vn.INPUT_TXN]=A,h[vn.APP_CALL_TXN]=x,T=t.assignGroupID(h),e.abrupt("return",[{txn:T[vn.INPUT_TXN],signers:[u]},{txn:T[vn.APP_CALL_TXN],signers:[u]}]);case 19:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Sn(e){return(yn[e]+1)*t.ALGORAND_MIN_TX_FEE}function On(){return(On=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return a=e.client,o=e.pool,i=e.txGroup,u=e.signedTxns,c=e.network,p=e.assetIn,t.next=3,nt(a,[u]);case 3:return l=t.sent,d=O(l,1),f=d[0],g=f.confirmedRound,I=f.txnID,A=[o.asset1ID,o.asset2ID].filter((function(t){return t!==p.id}))[0],t.prev=9,t.next=12,xe(a,i);case 12:x=t.sent,t.next=17;break;case 15:t.prev=15,t.t0=t.catch(9);case 17:return h=null===(n=x)||void 0===n||null===(r=n.find((function(t){return t.id===p.id})))||void 0===r?void 0:r.amount,T=null===(s=x)||void 0===s?void 0:s.find((function(t){return t.id===A})),t.t1=g,t.t2={amount:BigInt(p.amount)-BigInt(h||0),id:p.id},t.t3=T,t.next=24,ne.v2.getPoolInfo({client:a,network:c,asset1ID:o.asset1ID,asset2ID:o.asset2ID});case 24:return t.t4=t.sent,t.t5=I,t.abrupt("return",{round:t.t1,assetIn:t.t2,assetOut:t.t3,pool:t.t4,txnID:t.t5});case 27:case"end":return t.stop()}}),t,null,[[9,15]])})))).apply(this,arguments)}function Nn(t){var e=t.pool,n=t.assetIn,r=t.decimals;if(e.status!==Ct.READY)throw new X({pool:e,assetIn:n},"Trying to swap on a non-existent pool");var s,a,o,i=BigInt(n.amount),u=e.totalFeeShare;if(n.id===e.asset1ID)s=e.asset2ID,a=e.asset1Reserves,o=e.asset2Reserves;else{if(n.id!==e.asset2ID)throw new X({pool:e,assetIn:n},"Input asset (#".concat(n.id,") doesn't belong to the pool ").concat(e.account.address(),"."));s=e.asset1ID,a=e.asset2Reserves,o=e.asset1Reserves}var c=kn({inputSupply:a,outputSupply:o,swapInputAmount:i,totalFeeShare:u,decimals:r}),p=c.swapOutputAmount,l=c.totalFeeAmount,d=c.priceImpact;if(p>o)throw new bn;return{assetInID:n.id,assetInAmount:i,assetOutID:s,assetOutAmount:p,swapFee:Number(l),rate:Z(r.assetOut,Number(p))/Z(r.assetIn,Number(i)),priceImpact:d}}function Pn(t){var e=t.pool,n=t.assetOut,r=t.decimals;if(e.status!==Ct.READY)throw new X({pool:e,assetOut:n},"Trying to swap on a non-existent pool");var s,a,o,i=BigInt(n.amount),u=e.totalFeeShare;if(n.id===e.asset1ID)s=e.asset2ID,a=e.asset2Reserves,o=e.asset1Reserves;else{if(n.id!==e.asset2ID)throw new X({pool:e,assetOut:n},"Output asset (#".concat(n.id,") doesn't belong to the pool ").concat(e.account.address(),"."));s=e.asset1ID,a=e.asset1Reserves,o=e.asset2Reserves}var c=function(t){var e=t.inputSupply,n=t.outputSupply,r=t.swapOutputAmount,s=t.totalFeeShare,a=t.decimals,o=function(t){var e=t.inputSupply,n=t.outputSupply,r=t.outputAmount,s=e*n,a=BigInt(s/(n-r))-e;return a+=BigInt(1),a}({inputSupply:e,outputSupply:n,outputAmount:r}),i=function(t){var e=t.swapAmount,n=t.totalFeeShare,r=Math.floor(Number(e*BigInt(1e4)/(BigInt(1e4)-BigInt(n)))),s=BigInt(r)-e;return s}({swapAmount:o,totalFeeShare:s}),u=o+i,c=Xe({inputSupply:e,outputSupply:n,assetIn:{amount:u,decimals:a.assetIn},assetOut:{amount:r,decimals:a.assetOut}});return{swapInputAmount:u,totalFeeAmount:i,priceImpact:c}}({inputSupply:a,outputSupply:o,swapOutputAmount:i,totalFeeShare:u,decimals:r}),p=c.swapInputAmount,l=c.totalFeeAmount,d=c.priceImpact;if(i>o)throw new bn;return{assetInID:s,assetInAmount:p,assetOutID:n.id,assetOutAmount:i,swapFee:Number(l),rate:Z(r.assetOut,Number(i))/Z(r.assetIn,Number(p)),priceImpact:d}}function kn(t){var e=t.inputSupply,n=t.outputSupply,r=t.swapInputAmount,s=t.totalFeeShare,a=t.decimals,o=BigInt(function(t){var e=t.inputAmount,n=t.totalFeeShare;return Math.floor(Number(e*BigInt(n))/1e4)}({inputAmount:r,totalFeeShare:s})),i=function(t){var e=t.inputSupply,n=t.outputSupply,r=t.swapAmount,s=e*n,a=n-BigInt(s/(e+BigInt(r)));return a-=BigInt(1)}({inputSupply:e,outputSupply:n,swapAmount:r-o});return{swapOutputAmount:i,totalFeeAmount:o,priceImpact:Xe({inputSupply:e,outputSupply:n,assetIn:{amount:r,decimals:a.assetIn},assetOut:{amount:i,decimals:a.assetOut}})}}var Ln={getQuote:function(t,e,n,r){return t===Tn.FixedInput?Nn({pool:e,assetIn:n,decimals:r}):Pn({pool:e,assetOut:n,decimals:r})},getFixedInputSwapQuote:Nn,getFixedOutputSwapQuote:Pn,generateTxns:function(t){return En.apply(this,arguments)},signTxns:function(t){var e=t.txGroup;return(0,t.initiatorSigner)([e])},execute:function(t){return On.apply(this,arguments)},calculateFixedInputSwap:kn};function Fn(t,e){var n,r,s=BigInt(t),a=e.issuedLiquidity;return a>s+BigInt(jt)?(n=s*e.asset1/a,r=s*e.asset2/a):(n=e.asset1,r=e.asset2),{asset1OutputAmount:n,asset2OutputAmount:r}}function Bn(){return(Bn=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.pool,a=n.poolTokenIn,o=n.initiatorAddr,i=n.minAsset1Amount,u=n.minAsset2Amount,c=n.slippage,e.next=3,r.getTransactionParams().do();case 3:if(p=e.sent,l=s.account.address(),d=s.poolTokenID){e.next=8;break}throw new Error("Pool token asset ID is missing");case 8:return f=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:o,to:l,assetIndex:d,amount:a,suggestedParams:p}),(g=t.makeApplicationNoOpTxnFromObject({from:o,appIndex:s.validatorAppID,note:ht.getAppCallTxnNoteWithClientName(It.V2),appArgs:[dn,t.encodeUint64(H("negative",c,i)),t.encodeUint64(H("negative",c,u))],accounts:[l],foreignAssets:[s.asset1ID,s.asset2ID],suggestedParams:p})).fee=(ln+1)*t.ALGORAND_MIN_TX_FEE,(I=[])[fn.ASSET_TRANSFER_TXN]=f,I[fn.APP_CALL_TXN]=g,A=t.assignGroupID(I),e.abrupt("return",[{txn:A[fn.ASSET_TRANSFER_TXN],signers:[o]},{txn:A[fn.APP_CALL_TXN],signers:[o]}]);case 16:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Rn(){return(Rn=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T,v,y;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.pool,a=n.initiatorAddr,o=n.poolTokenIn,i=n.outputAssetId,u=n.minOutputAssetAmount,c=n.slippage,e.next=3,r.getTransactionParams().do();case 3:if(p=e.sent,l=s.asset1ID,d=s.asset2ID,f=s.account.address(),g=s.poolTokenID){e.next=9;break}throw new Error("Pool token asset ID is missing");case 9:if(I=0,A=0,x=H("negative",c,u),i!==l){e.next=17;break}I=x,A=0,e.next=23;break;case 17:if(i!==d){e.next=22;break}I=0,A=x,e.next=23;break;case 22:throw new Error("Invalid output asset id. It doesn't match with pool assets");case 23:return h=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:a,to:f,assetIndex:g,amount:o,suggestedParams:p}),(T=t.makeApplicationNoOpTxnFromObject({from:a,appIndex:s.validatorAppID,note:ht.getAppCallTxnNoteWithClientName(It.V2),appArgs:[dn,t.encodeUint64(I),t.encodeUint64(A)],accounts:[f],foreignAssets:[i],suggestedParams:p})).fee=(ln+1)*t.ALGORAND_MIN_TX_FEE,(v=[])[fn.ASSET_TRANSFER_TXN]=h,v[fn.APP_CALL_TXN]=T,y=t.assignGroupID(v),e.abrupt("return",[{txn:y[fn.ASSET_TRANSFER_TXN],signers:[a]},{txn:y[fn.APP_CALL_TXN],signers:[a]}]);case 31:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Mn(){return(Mn=I(m().mark((function t(e){var n,r,s,a,o,i,u;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.txGroup,s=e.signedTxns,t.next=3,nt(n,[s]);case 3:return a=t.sent,o=O(a,1),i=o[0].txnID,t.prev=6,t.next=9,xe(n,r);case 9:u=t.sent,t.next=14;break;case 12:t.prev=12,t.t0=t.catch(6);case 14:return t.abrupt("return",{outputAssets:u,txnID:i});case 15:case"end":return t.stop()}}),t,null,[[6,12]])})))).apply(this,arguments)}var Cn,Xn={getQuote:function(t){var e=t.pool,n=t.reserves,r=t.poolTokenIn,s=BigInt(r),a=Fn(s,n),o=a.asset1OutputAmount,i=a.asset2OutputAmount;return{round:n.round,asset1Out:{assetId:e.asset1ID,amount:o},asset2Out:{assetId:e.asset2ID,amount:i},poolTokenIn:{assetId:e.poolTokenID,amount:s}}},getSingleAssetRemoveLiquidityQuote:function(t){var e,n=t.pool,r=t.reserves,s=t.poolTokenIn,a=t.assetOutID,o=t.decimals,i=BigInt(s),u=Fn(i,r),c=u.asset1OutputAmount,p=u.asset2OutputAmount,l=n.totalFeeShare;if(a===n.asset1ID){var d=Ln.calculateFixedInputSwap({inputSupply:r.asset2-p,outputSupply:r.asset1-c,swapInputAmount:p,totalFeeShare:l,decimals:o}),f=d.swapOutputAmount,m=d.totalFeeAmount,g=d.priceImpact;e={round:r.round,assetOut:{assetId:a,amount:c+f},poolTokenIn:{assetId:n.poolTokenID,amount:i},internalSwapQuote:{amountIn:{assetId:n.asset2ID,amount:p},amountOut:{assetId:n.asset1ID,amount:f},swapFees:{assetId:n.asset2ID,amount:m},priceImpact:g}}}else{if(a!==n.asset2ID)throw new Error("assetOutID must be one of the pool assets");var I=Ln.calculateFixedInputSwap({inputSupply:r.asset1-c,outputSupply:r.asset2-p,swapInputAmount:c,totalFeeShare:l,decimals:o}),A=I.swapOutputAmount,x=I.totalFeeAmount,h=I.priceImpact;e={round:r.round,assetOut:{assetId:a,amount:p+A},poolTokenIn:{assetId:n.poolTokenID,amount:i},internalSwapQuote:{amountIn:{assetId:n.asset2ID,amount:p},amountOut:{assetId:n.asset1ID,amount:A},swapFees:{assetId:n.asset2ID,amount:x},priceImpact:h}}}return e},generateTxns:function(t){return Bn.apply(this,arguments)},generateSingleAssetOutTxns:function(t){return Rn.apply(this,arguments)},signTxns:function(t){var e=t.txGroup;return(0,t.initiatorSigner)([e])},execute:function(t){return Mn.apply(this,arguments)}},jn=(T(Cn={},It.V1_1,hn),T(Cn,It.V2,Xn),Cn),Vn=3n,Qn=1000n,Un=function(t){return t[t.FEE_TXN_INDEX=0]="FEE_TXN_INDEX",t[t.VALIDATOR_APP_CALL_TXN_INDEX=1]="VALIDATOR_APP_CALL_TXN_INDEX",t[t.ASSET_IN_TXN_INDEX=2]="ASSET_IN_TXN_INDEX",t[t.ASSET_OUT_TXN_INDEX=3]="ASSET_OUT_TXN_INDEX",t}(Un||{});function Gn(){return(Gn=I(m().mark((function e(n){var r,s,a,o,i,u,c,p;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.pool,s=n.txGroup,a=n.initiatorSigner,e.next=3,a([s]);case 3:return o=e.sent,i=O(o,2),u=i[0],c=i[1],p=s.map((function(e,n){return n===Un.FEE_TXN_INDEX?u:n===Un.ASSET_IN_TXN_INDEX?c:t.signLogicSigTransactionObject(e.txn,r.account.lsig).blob})),e.abrupt("return",p);case 9:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Wn(){return(Wn=I(m().mark((function e(r){var s,a,o,i,u,c,p,l,d,f,g,I,A,x,h,T,v,y;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(s=r.client,a=r.pool,o=r.swapType,i=r.assetIn,u=r.assetOut,c=r.slippage,p=r.initiatorAddr,l=a.account.address(),(d=[a.asset1ID,a.asset2ID]).includes(i.id)&&d.includes(u.id)&&i.id!==u.id){e.next=5;break}throw new X({pool:a,assetIn:i,assetOut:u},"Input asset (#".concat(i.id,") and output asset (#").concat(u.id,") provided to generate transactions do not belong to the pool ").concat(l,"."));case 5:return e.next=7,s.getTransactionParams().do();case 7:return f=e.sent,g=[it("swap"),o===Tn.FixedInput?it("fi"):it("fo")],I=t.makeApplicationNoOpTxnFromObject({from:l,appIndex:a.validatorAppID,appArgs:g,accounts:[p],note:ht.getAppCallTxnNoteWithClientName(It.V1_1),foreignAssets:a.asset2ID==ut?[a.asset1ID,a.poolTokenID]:[a.asset1ID,a.asset2ID,a.poolTokenID],suggestedParams:f}),A=o===Tn.FixedOutput?H("positive",c,i.amount):i.amount,x=i.id===ut?t.makePaymentTxnWithSuggestedParamsFromObject({from:p,to:l,amount:A,suggestedParams:f}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:p,to:l,assetIndex:i.id,amount:A,suggestedParams:f}),h=o===Tn.FixedInput?H("negative",c,u.amount):u.amount,T=u.id===ut?t.makePaymentTxnWithSuggestedParamsFromObject({from:l,to:p,amount:h,suggestedParams:f}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:l,to:p,assetIndex:u.id,amount:h,suggestedParams:f}),v=t.makePaymentTxnWithSuggestedParamsFromObject({from:p,to:l,amount:I.fee+T.fee,note:n,suggestedParams:f}),y=t.assignGroupID([v,I,x,T]),e.abrupt("return",[{txn:y[0],signers:[p]},{txn:y[1],signers:[l]},{txn:y[2],signers:[p]},{txn:y[3],signers:[l]}]);case 17:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function qn(t){var e=t.pool,n=t.reserves,r=t.assetIn,s=t.decimals;if(e.status!==Ct.READY)throw new X({pool:e,assetIn:r},"Trying to swap on a non-existent pool");var a,o,i,u=BigInt(r.amount);if(r.id===e.asset1ID)a=e.asset2ID,o=n.asset1,i=n.asset2;else{if(r.id!==e.asset2ID)throw new X({pool:e,assetIn:r},"Input asset (#".concat(r.id,") doesn't belong to the pool ").concat(e.account.address(),"."));a=e.asset1ID,o=n.asset2,i=n.asset1}var c=u*Vn/Qn,p=i-o*i/(o+(u-c));if(p>i)throw new bn;var l={assetIn:{amount:u,decimals:s.assetIn},assetOut:{amount:p,decimals:s.assetOut}};return{round:n.round,assetInID:r.id,assetInAmount:u,assetOutID:a,assetOutAmount:p,swapFee:Number(c),rate:Ce(l),priceImpact:Xe(f({inputSupply:o,outputSupply:i},l))}}function zn(t){return Jn.apply(this,arguments)}function Jn(){return(Jn=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l,d,f,g,I,A,x;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.signedTxns,a=e.assetIn,o=e.assetOut,i=e.initiatorAddr,t.next=3,Ft({client:n,pool:r,accountAddr:i});case 3:return u=t.sent,t.next=6,nt(n,[s]);case 6:return c=t.sent,p=O(c,1),l=p[0],d=l.confirmedRound,f=l.txnID,t.next=13,Ft({client:n,pool:r,accountAddr:i});case 13:return g=t.sent,o.id===r.asset1ID?(I=u.excessAsset1,A=g.excessAsset1):(I=u.excessAsset2,A=g.excessAsset2),(x=A-I)<0n&&(x=0n),t.abrupt("return",{round:d,assetInID:a.id,assetInAmount:BigInt(a.amount),assetOutID:o.id,assetOutAmount:BigInt(o.amount)+x,excessAmount:{assetID:o.id,excessAmountForSwap:x,totalExcessAmount:A},txnID:f});case 18:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Yn(t){var e=t.pool,n=t.reserves,r=t.assetOut,s=t.decimals;if(e.status!==Ct.READY)throw new X({pool:e,assetOut:r},"Trying to swap on a non-existent pool");var a,o,i,u=BigInt(r.amount);if(r.id===e.asset1ID)a=e.asset2ID,o=n.asset2,i=n.asset1;else{if(r.id!==e.asset2ID)throw new X({pool:e,assetOut:r},"Output asset (#".concat(r.id,") doesn't belong to the pool ").concat(e.account.address(),"."));a=e.asset1ID,o=n.asset1,i=n.asset2}if(u>i)throw new bn;var c=o*i/(i-u)-o,p=c*Qn/(Qn-Vn),l=p-c,d=Z(s.assetOut,Number(u))/Z(s.assetIn,Number(p)),f=Z(s.assetOut,Number(i))/Z(s.assetIn,Number(o)),m=$({decimalPlaces:5},Math.abs(d/f-1));return{round:n.round,assetInID:a,assetInAmount:p,assetOutID:r.id,assetOutAmount:u,swapFee:Number(l),rate:d,priceImpact:m}}function Kn(t){return Hn.apply(this,arguments)}function Hn(){return(Hn=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l,d,f,g,I,A,x;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.signedTxns,a=e.assetIn,o=e.assetOut,i=e.initiatorAddr,t.next=3,Ft({client:n,pool:r,accountAddr:i});case 3:return u=t.sent,t.next=6,nt(n,[s]);case 6:return c=t.sent,p=O(c,1),l=p[0],d=l.confirmedRound,f=l.txnID,t.next=13,Ft({client:n,pool:r,accountAddr:i});case 13:return g=t.sent,a.id===r.asset1ID?(I=u.excessAsset1,A=g.excessAsset1):(I=u.excessAsset2,A=g.excessAsset2),(x=A-I)<0n&&(x=0n),t.abrupt("return",{round:d,assetInID:a.id,assetInAmount:BigInt(a.amount)-x,assetOutID:o.id,assetOutAmount:BigInt(o.amount),excessAmount:{assetID:a.id,excessAmountForSwap:x,totalExcessAmount:A},txnID:f});case 18:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Zn(){return(Zn=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(n=e.client,r=e.pool,s=e.swapType,a=e.txGroup,o=e.signedTxns,i=e.initiatorAddr,r.status===Ct.READY){t.next=3;break}throw new X({pool:r,swapType:s,txGroup:a},"Trying to swap on a non-existent pool");case 3:if(t.prev=3,u={id:a[Un.ASSET_IN_TXN_INDEX].txn.assetIndex||ut,amount:a[Un.ASSET_IN_TXN_INDEX].txn.amount},c={id:a[Un.ASSET_OUT_TXN_INDEX].txn.assetIndex||ut,amount:a[Un.ASSET_OUT_TXN_INDEX].txn.amount},s!==Tn.FixedInput){t.next=12;break}return t.next=9,zn({client:n,pool:r,signedTxns:o,assetIn:u,assetOut:c,initiatorAddr:i});case 9:p=t.sent,t.next=15;break;case 12:return t.next=14,Kn({client:n,pool:r,signedTxns:o,assetIn:u,assetOut:c,initiatorAddr:i});case 14:p=t.sent;case 15:return t.abrupt("return",f(f({},p),{},{groupID:at(a),fees:st(a)}));case 18:throw t.prev=18,t.t0=t.catch(3),"SlippageTolerance"===(l=new X(t.t0,"We encountered something unexpected while swapping. Try again later.")).type&&l.setMessage("The swap failed due to too much slippage in the price. Please adjust the slippage tolerance and try again."),l;case 23:case"end":return t.stop()}}),t,null,[[3,18]])})))).apply(this,arguments)}var $n,tr={getQuote:function(t,e,n,r,s){return t===Tn.FixedInput?qn({pool:e,reserves:n,assetIn:r,decimals:s}):Yn({pool:e,reserves:n,assetOut:r,decimals:s})},getFixedInputSwapQuote:qn,getFixedOutputSwapQuote:Yn,generateTxns:function(t){return Wn.apply(this,arguments)},signTxns:function(t){return Gn.apply(this,arguments)},execute:function(t){return Zn.apply(this,arguments)},executeFixedOutputSwap:Kn},er=4*t.ALGORAND_MIN_TX_FEE;function nr(t){return Promise.allSettled(t).then((function(t){if(t.every((function(t){return"rejected"===t.status&&t.reason instanceof bn})))throw new bn;return t.filter((function(t){return"fulfilled"===t.status&&void 0!==t.value.quote})).map((function(t){return t.value}))}))}function rr(){return(rr=I(m().mark((function t(e){var n,r,s,a,o,i;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.pools,r=e.assetIn,s=e.assetOut,a=e.amount,o=n.map((function(t){return new Promise((function(e,n){var o,i={pool:t.info,assetIn:{amount:a,id:Number(r.id)},decimals:{assetIn:r.decimals,assetOut:s.decimals},reserves:t.reserves};try{o=t.info.contractVersion===It.V1_1?tr.getFixedInputSwapQuote(i):Ln.getFixedInputSwapQuote(i),e({pool:t,quote:o})}catch(t){n(t)}}))})),t.next=4,nr(o);case 4:return i=t.sent,t.abrupt("return",ar(i));case 6:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function sr(){return(sr=I(m().mark((function t(e){var n,r,s,a,o,i;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.pools,r=e.assetIn,s=e.assetOut,a=e.amount,o=n.map((function(t){return new Promise((function(e,n){var o,i={pool:t.info,assetOut:{amount:a,id:Number(s.id)},decimals:{assetIn:r.decimals,assetOut:s.decimals},reserves:t.reserves};try{o=t.info.contractVersion===It.V1_1?tr.getFixedOutputSwapQuote(i):Ln.getFixedOutputSwapQuote(i),e({pool:t,quote:o})}catch(t){n(t)}}))})),t.next=4,nr(o);case 4:return i=t.sent,t.abrupt("return",ar(i));case 6:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function ar(t){return t.filter((function(t){return!$t(t.pool.reserves)})).sort((function(t,e){return e.quote.rate-t.quote.rate}))[0]}var or=(T($n={},It.V1_1,tr),T($n,It.V2,Ln),T($n,"getQuote",(function(t){if(t.pools.every((function(t){return $t(t.reserves)})))throw new Error("No pools available for swap");return t.type===Tn.FixedInput?function(t){return rr.apply(this,arguments)}(t):function(t){return sr.apply(this,arguments)}(t)})),T($n,"generateTxns",(function(t){return t.pool.contractVersion===It.V1_1?tr.generateTxns(t):Ln.generateTxns(t)})),T($n,"signTxns",(function(t){return t.pool.contractVersion===It.V1_1?tr.signTxns(t):Ln.signTxns(t)})),T($n,"execute",(function(t){return t.contractVersion===It.V1_1?tr.execute(t):Ln.execute(t)})),$n);function ir(){return(ir=I(m().mark((function t(e){var n,r,s,a,o,i,u,c,p,l;return m().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.txGroup,a=e.initiatorSigner,t.prev=1,t.next=4,ur({txGroup:s,pool:r,initiatorSigner:a});case 4:return o=t.sent,t.next=7,nt(n,[o]);case 7:return i=t.sent,u=O(i,1),c=u[0],p=c.txnID,l=c.confirmedRound,t.abrupt("return",{fees:st(s),confirmedRound:l,txnID:p,groupID:at(s)});case 15:throw t.prev=15,t.t0=t.catch(1),new X(t.t0,"We encountered something unexpected while redeeming. Try again later.");case 18:case"end":return t.stop()}}),t,null,[[1,15]])})))).apply(this,arguments)}function ur(t){return cr.apply(this,arguments)}function cr(){return(cr=I(m().mark((function e(n){var r,s,a,o,i,u,c,p;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.txGroup,s=n.pool,a=n.initiatorSigner,e.next=3,a([r]);case 3:return o=e.sent,i=O(o,1),u=i[0],c=s.account.lsig,p=r.map((function(e,n){return 0===n?u:t.signLogicSigTransactionObject(e.txn,c).blob})),e.abrupt("return",p);case 9:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function pr(){return pr=I(m().mark((function e(n){var r,s,a,o,i,u;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.data,a=n.initiatorSigner,e.prev=1,o=s.map((function(t){var e=t.txGroup,n=t.pool;return{txns:e,txnFees:st(e),groupID:at(e),lsig:n.account.lsig}})),e.next=5,a(o.map((function(t){return t.txns})));case 5:return i=e.sent,u=Promise.all(o.map((function(e,n){return new Promise(function(){var s=I(m().mark((function s(a,o){var u,c,p,l,d,f;return m().wrap((function(s){for(;;)switch(s.prev=s.next){case 0:return s.prev=0,u=e.txns.map((function(r,s){return 0===s?i[n]:t.signLogicSigTransactionObject(r.txn,e.lsig).blob})),s.next=4,nt(r,[u]);case 4:c=s.sent,p=O(c,1),l=p[0],d=l.txnID,f=l.confirmedRound,a({fees:e.txnFees,groupID:e.groupID,txnID:d,confirmedRound:f}),s.next=15;break;case 12:s.prev=12,s.t0=s.catch(0),o(s.t0);case 15:case"end":return s.stop()}}),s,null,[[0,12]])})));return function(t,e){return s.apply(this,arguments)}}())}))),e.abrupt("return",u);case 10:throw e.prev=10,e.t0=e.catch(1),new X(e.t0,"We encountered something unexpected while redeeming. Try again later.");case 13:case"end":return e.stop()}}),e,null,[[1,10]])}))),pr.apply(this,arguments)}function lr(){return(lr=I(m().mark((function e(r){var s,a,o,i,u,c,p,l,d,f,g;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return s=r.client,a=r.pool,o=r.assetID,i=r.assetOut,u=r.initiatorAddr,e.next=3,s.getTransactionParams().do();case 3:return c=e.sent,p=a.account.address(),l=t.makeApplicationNoOpTxnFromObject({from:p,appIndex:a.validatorAppID,appArgs:[it("redeem")],note:ht.getAppCallTxnNoteWithClientName(a.contractVersion),accounts:[u],foreignAssets:0==a.asset2ID?[a.asset1ID,a.poolTokenID]:[a.asset1ID,a.asset2ID,a.poolTokenID],suggestedParams:c}),d=0===o?t.makePaymentTxnWithSuggestedParamsFromObject({from:p,to:u,amount:BigInt(i),suggestedParams:c}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:p,to:u,assetIndex:o,amount:BigInt(i),suggestedParams:c}),f=t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:p,amount:l.fee+d.fee,note:n,suggestedParams:c}),g=t.assignGroupID([f,l,d]),e.abrupt("return",[{txn:g[0],signers:[u]},{txn:g[1],signers:[p]},{txn:g[2],signers:[p]}]);case 10:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function dr(e){var n=e.suggestedParams,r=e.stakingAppID,s=e.initiatorAddr,a=e.liquidityAssetID,o=e.program,i=e.amount,u=t.encodeUint64(i),c=t.encodeUint64(o.id);return t.makeApplicationNoOpTxnFromObject({appIndex:r,from:s,suggestedParams:n,foreignAssets:[a],accounts:[o.accountAddress],appArgs:[it("commit"),u],note:V([it("tinymanStaking/v1:b"),c,t.encodeUint64(a),u])})}function fr(){return(fr=I(m().mark((function e(n){var r,s,a,o,i,u,c,p,l,d,f;return m().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.stakingAppID,a=n.program,o=n.requiredAssetID,i=n.liquidityAssetID,u=n.amount,c=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:if(p=e.sent,l=dr({suggestedParams:p,stakingAppID:s,program:a,liquidityAssetID:i,initiatorAddr:c,amount:u}),d=[l],"number"!=typeof o){e.next=10;break}return f=t.makeApplicationNoOpTxnFromObject({appIndex:s,from:c,suggestedParams:p,foreignAssets:[o],accounts:[a.accountAddress],appArgs:[it("log_balance")]}),d=t.assignGroupID([l,f]),e.abrupt("return",[{txn:d[0],signers:[c]},{txn:d[1],signers:[c]}]);case 10:return e.abrupt("return",[{txn:d[0],signers:[c]}]);case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}exports.ALGO_ASSET=ct,exports.ALGO_ASSET_ID=ut,exports.ASSET_OPT_IN_PROCESS_TXN_COUNT=1,exports.AddLiquidity=un,exports.BASE_MINIMUM_BALANCE=r,exports.Bootstrap=Pe,exports.CONTRACT_VERSION=It,exports.MINIMUM_ADD_LIQUIDITY_AMOUNT=p,exports.MINIMUM_BALANCE_REQUIRED_PER_APP=a,exports.MINIMUM_BALANCE_REQUIRED_PER_ASSET=s,exports.MINIMUM_BALANCE_REQUIRED_PER_BYTE_SCHEMA=u,exports.MINIMUM_BALANCE_REQUIRED_PER_INT_SCHEMA_VALUE=c,exports.OPT_IN_VALIDATOR_APP_PROCESS_TXN_COUNT=1,exports.OPT_OUT_VALIDATOR_APP_PROCESS_TXN_COUNT=1,exports.POOL_TOKEN_UNIT_NAME=pt,exports.PoolStatus=Ct,exports.REDEEM_PROCESS_TXN_COUNT=3,exports.RemoveLiquidity=jn,exports.Swap=or,exports.SwapType=Tn,exports.V1_1AddLiquidityTxnIndices=ke,exports.V1_1_ADD_LIQUIDITY_PROCESS_TXN_COUNT=5,exports.V1_1_REMOVE_LIQUIDITY_TXN_COUNT=pn,exports.V2AddLiquidityTxnIndices=Be,exports.V2AddLiquidityType=Fe,exports.V2_REMOVE_LIQUIDITY_APP_CALL_INNER_TXN_COUNT=ln,exports.applySlippageToAmount=H,exports.calculateAccountMinimumRequiredBalance=kt,exports.combineAndRegroupSignerTxns=function(){for(var e=arguments.length,n=new Array(e),r=0;r=t.minimum_required_balance},exports.isAccountOptedIntoApp=function(t){var e=t.appID;return t.accountAppsLocalState.some((function(t){return t.id===e}))},exports.poolUtils=ne,exports.prepareCommitTransactions=function(t){return fr.apply(this,arguments)},exports.redeemAllExcessAsset=function(t){return pr.apply(this,arguments)},exports.redeemExcessAsset=function(t){return ir.apply(this,arguments)},exports.sendAndWaitRawTransaction=nt,exports.sumUpTxnFees=st,exports.tinymanContract_v1_1=Dt,exports.tinymanContract_v2=St,exports.tinymanJSSDKConfig=ht; +"use strict";var t=require("algosdk"),e=require("base64-js");function n(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function r(t){for(var e=1;e=0;--a){var s=this.tryEntries[a],o=s.completion;if("root"===s.tryLoc)return r("end");if(s.tryLoc<=this.prev){var i=n.call(s,"catchLoc"),u=n.call(s,"finallyLoc");if(i&&u){if(this.prev=0;--r){var a=this.tryEntries[r];if(a.tryLoc<=this.prev&&n.call(a,"finallyLoc")&&this.prev=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),b(n),d}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var r=n.completion;if("throw"===r.type){var a=r.arg;b(n)}return a}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:D(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=void 0),d}},t}function s(t,e,n,r,a,s,o){try{var i=t[s](o),u=i.value}catch(t){return void n(t)}i.done?e(u):Promise.resolve(u).then(r,a)}function o(t){return function(){var e=this,n=arguments;return new Promise((function(r,a){var o=t.apply(e,n);function i(t){s(o,r,a,i,u,"next",t)}function u(t){s(o,r,a,i,u,"throw",t)}i(void 0)}))}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,o=!0,i=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return o=t.done,t},e:function(t){i=!0,s=t},f:function(){try{o||null==n.return||n.return()}finally{if(i)throw s}}}}function _(t){var e=function(t,e){if("object"!=typeof t||null===t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var r=n.call(t,e||"default");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"==typeof e?e:String(e)}var b=function(t){return t.SwapRouterStaleDataError="SwapRouterStaleDataError",t.SwapRouterNoRouteError="SwapRouterNoRouteError",t.SwapRouterLowSwapAmountError="SwapRouterLowSwapAmountError",t.SwapRouterInsufficientReservesError="SwapRouterInsufficientReservesError",t.SwapRouterPoolHasNoLiquidityError="SwapRouterPoolHasNoLiquidityError",t.NoAvailablePoolError="NoAvailablePoolError",t.OutputAmountExceedsAvailableLiquidityError="OutputAmountExceedsAvailableLiquidityError",t.UnknownError="UnknownError",t.LowSwapAmountError="LowSwapAmountError",t.AssetDoesNotBelongToPoolError="AssetDoesNotBelongToPoolError",t.InvalidSwapTypeError="InvalidSwapTypeError",t}({}),E=function(t){l(n,A(Error));var e=x(n);function n(t,r){var a;return i(this,n),(a=e.call(this,r)).type=t,a.message=r,Error.captureStackTrace&&Error.captureStackTrace(I(a),n),a}return c(n)}(),D=Uint8Array.from([1]),S=1e5,O=1e5,N=1e5,P=1e5,k=1e5,L=5e4,R=28500,F=1e3,B=1e3,M={mainnet:{base:"https://mainnet.analytics.tinyman.org/api",v1:"https://mainnet.analytics.tinyman.org/api/v1"},testnet:{base:"https://testnet.analytics.tinyman.org/api",v1:"https://testnet.analytics.tinyman.org/api/v1"}},C={V1_1:"v1_1",V2:"v2"},j=0,V={id:"".concat(j),name:"Algorand",unit_name:"ALGO",decimals:6,url:"https://algorand.org",is_liquidity_token:!1,total_amount:"6615503326932151",clawback_address:""},X={V1:"TM1POOL",V1_1:"TMPOOL11",V2:"TMPOOL2"},Q="- would result negative",U="logic eval error:",q="exceeds schema integer count",G=/transaction \w+:/,W=function(t){l(n,A(Error));var e=x(n);function n(t,r){var a;i(this,n);for(var s=arguments.length,o=new Array(s>2?s-2:0),u=2;ua?[r(r({},t),{},{id:n}),r(r({},e),{},{id:a})]:[r(r({},e),{},{id:a}),r(r({},t),{},{id:n})]}function Y(t,e){var n=[t,e];return[Math.max.apply(Math,n),Math.min.apply(Math,n)]}function K(t){return Number(t)===j}function H(t){return Number(t.id)}function Z(t){var e,n=t.stateArray,r=void 0===n?[]:n,a=t.shouldDecodeKeys,s=void 0!==a&&a,o={},i=w(r);try{for(i.s();!(e=i.n()).done;){var u=e.value,c=u.key,p=void 0;if(1==u.value.type)p=u.value.bytes;else{if(2!=u.value.type)throw new Error("Unexpected state type: ".concat(u.value.type));p=u.value.uint}o[s?atob(c):c]=p}}catch(t){i.e(t)}finally{i.f()}return o}function $(t){var e,n=t.reduce((function(t,e){return t+e.length}),0),r=new Uint8Array(n),a=0,s=w(t);try{for(s.s();!(e=s.n()).done;){var o=e.value;r.set(o,a),a+=o.length}}catch(t){s.e(t)}finally{s.f()}return r}var tt=100000n,et=100000n,nt=100000n,rt=25000n+25000n,at=25000n+3500n;function st(t){var e=t["apps-total-schema"],n=0n,r=0n;e&&(e["num-byte-slice"]&&(n=e["num-byte-slice"]),e["num-uint"]&&(r=e["num-uint"]));var a=t["apps-local-state"]||[],s=t["created-apps"]||[],o=t.assets||[];return tt+et*BigInt(o.length)+nt*BigInt(s.length+a.length)+at*r+rt*n}function ot(t){return new Promise((function(e){setTimeout((function(){e(null)}),t)}))}function it(t,e){return ut.apply(this,arguments)}function ut(){return(ut=o(a().mark((function t(e,n){var r;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=3,ot(1e3);case 3:return r=null,t.prev=4,t.next=7,e.pendingTransactionInformation(n).do();case 7:r=t.sent,t.next=12;break;case 10:t.prev=10,t.t0=t.catch(4);case 12:if(!r){t.next=17;break}if(!r["confirmed-round"]){t.next=15;break}return t.abrupt("return",r);case 15:if(!r["pool-error"]){t.next=17;break}throw new Error("Transaction Rejected: ".concat(r["pool-error"]));case 17:t.next=0;break;case 19:case"end":return t.stop()}}),t,null,[[4,10]])})))).apply(this,arguments)}function ct(t,e,n){if(e>1||e<0)throw new Error("Invalid slippage value. Must be between 0 and 1, got ".concat(e));var r;try{var a="negative"===t?1-e:1+e;r=BigInt(Math.floor(Number(n)*a))}catch(t){throw new Error(t.message)}return r}function pt(t,e){var n=Number(t);return lt({decimalPlaces:n},Math.pow(10,-n)*Number(e))}function lt(t,e){var n=t.decimalPlaces,r=void 0===n?0:n;if(r>0){var a=h(ft(e),2),s=a[0],o=a[1],i=h(ft(Math.round(Number(dt(s,o+r)))),2),u=i[0],c=i[1];return Number(dt(u,c-r))}return Math.round(e)}function dt(t,e){return t+(e<0?"e".concat(e):"e+".concat(e))}function ft(t){if(t.toString().includes("e")){var e=t.toString().split("e");return[parseFloat(e[0]),parseFloat(e[1])]}return[t,0]}function mt(t,e){return gt.apply(this,arguments)}function gt(){return(gt=o(a().mark((function t(e,n){var r,s,o,i,u,c,p,l;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:t.prev=0,r=[],s=w(n),t.prev=3,s.s();case 5:if((o=s.n()).done){t.next=18;break}return i=o.value,t.next=9,e.sendRawTransaction(i).do();case 9:return u=t.sent,c=u.txId,t.next=13,it(e,c);case 13:p=t.sent,l=p["confirmed-round"],r.push({confirmedRound:l,txnID:c});case 16:t.next=5;break;case 18:t.next=23;break;case 20:t.prev=20,t.t0=t.catch(3),s.e(t.t0);case 23:return t.prev=23,s.f(),t.finish(23);case 26:return t.abrupt("return",r);case 29:throw t.prev=29,t.t1=t.catch(0),new W(t.t1,"We encountered an error while processing this transaction. Try again later.");case 32:case"end":return t.stop()}}),t,null,[[0,29],[3,20,23,26]])})))).apply(this,arguments)}function At(t){return t.reduce((function(t,e){return t+e.txn.fee}),0)}function It(t){return(e=t[0].txn.group)?Buffer.from(e).toString("base64"):"";var e}function xt(t){for(var e=[];;){var n=127&t;if(!(t>>=7)){e.push(n);break}e.push(128|n)}return e}function ht(t){return(new TextEncoder).encode(t)}var vt,Tt=new(function(){function t(){i(this,t),this.clientName="tinyman-js-sdk"}return c(t,[{key:"getClientName",value:function(){return this.clientName}},{key:"setClientName",value:function(t){this.clientName=t}},{key:"getAppCallTxnNoteWithClientName",value:function(t){var e=t===C.V1_1?"v1":t;return ht("tinyman/".concat(e,':j{"origin":"').concat(this.clientName,'"}'))}}]),t}()),yt=(p(vt={},C.V1_1,{testnet:62368684,mainnet:552635992}),p(vt,C.V2,{testnet:148607e3,mainnet:1002541853}),vt);function wt(t,e){var n=yt[e][t];if(!n)throw new Error("No Validator App exists for ".concat(t," network with ").concat(e," contract version"));return n}function _t(){return(_t=o(a().mark((function e(n){var r,s,o,i,u,c;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,o=n.contractVersion,i=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return u=e.sent,c=t.makeApplicationOptInTxnFromObject({from:i,appIndex:wt(s,o),note:Tt.getAppCallTxnNoteWithClientName(o),suggestedParams:u}),e.abrupt("return",[{txn:c,signers:[i]}]);case 6:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function bt(){return(bt=o(a().mark((function e(n){var r,s,o,i,u,c;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,o=n.contractVersion,i=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return u=e.sent,c=t.makeApplicationClearStateTxnFromObject({from:i,appIndex:wt(s,o),note:Tt.getAppCallTxnNoteWithClientName(o),suggestedParams:u}),e.abrupt("return",[{txn:c,signers:[i]}]);case 6:case"end":return e.stop()}}),e)})))).apply(this,arguments)}var Et,Dt,St,Ot=function(t){return t.FixedInput="fixed-input",t.FixedOutput="fixed-output",t}({}),Nt=.003,Pt=function(t){return t[t.INPUT_TXN=0]="INPUT_TXN",t[t.APP_CALL_TXN=1]="APP_CALL_TXN",t}({}),kt=(p(Et={},Ot.FixedInput,1),p(Et,Ot.FixedOutput,2),Et),Lt=2,Rt=ht("swap"),Ft=(p(Dt={},Ot.FixedInput,ht("fixed-input")),p(Dt,Ot.FixedOutput,ht("fixed-output")),Dt),Bt={ASSET_OPT_IN:ht("asset_opt_in")},Mt={testnet:184778019,mainnet:1083651166},Ct=(p(St={},Ot.FixedInput,7),p(St,Ot.FixedOutput,8),St);function jt(t){var e=Ut(t),n=e.assetIn,r=e.assetOut;return pt(r.asset.decimals,Number(r.amount))/pt(n.asset.decimals,Number(n.amount))}function Vt(t){var e=Mt[t];if(!e)throw new Error("Unknown network or network not supported: ".concat(t));return e}function Xt(t){return t[t.length-1].quote.amount_out}function Qt(t){return t[0].quote.amount_in}function Ut(t){return{assetIn:Qt(t),assetOut:Xt(t)}}function qt(t){return Gt.apply(this,arguments)}function Gt(){return(Gt=o(a().mark((function e(n){var r,s,o,i,u,c,p;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.routerAppID,o=n.assetIDs,i=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return u=e.sent,c=t.makeApplicationNoOpTxnFromObject({from:i,appIndex:s,appArgs:[Bt.ASSET_OPT_IN],foreignAssets:o,suggestedParams:u}),p=o.length,c.fee=t.ALGORAND_MIN_TX_FEE*(p+1),e.abrupt("return",c);case 8:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Wt(t){return zt.apply(this,arguments)}function zt(){return(zt=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,h,v,T,y,w,_,b,E,D,S,O,N;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.initiatorAddr,s=n.client,o=n.network,i=n.swapType,u=n.route,c=n.slippage,e.next=3,s.getTransactionParams().do();case 3:return p=e.sent,l=[H(u[0].quote.amount_in.asset),H(u[0].quote.amount_out.asset),H(u[1].quote.amount_out.asset)],d=l[0],f=l[1],m=l[2],g=[Number(Qt(u).amount),Number(Xt(u).amount)],A=g[0],I=g[1],x=[u[0].pool.address,u[1].pool.address],h=x[0],v=x[1],T=i===Ot.FixedInput?A:ct("positive",c,A),y=i===Ot.FixedOutput?I:ct("negative",c,I),w=K(d),_=Vt(o),b=w?t.makePaymentTxnWithSuggestedParamsFromObject({from:r,to:t.getApplicationAddress(_),amount:T,suggestedParams:p}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:r,to:t.getApplicationAddress(_),amount:T,assetIndex:d,suggestedParams:p}),(E=t.makeApplicationNoOpTxnFromObject({from:r,appIndex:_,appArgs:[Rt,Ft[i],t.encodeUint64(y)],foreignApps:[wt(o,C.V2)],foreignAssets:[d,f,m],accounts:[h,v],suggestedParams:p,note:Tt.getAppCallTxnNoteWithClientName(C.V2)})).fee=t.ALGORAND_MIN_TX_FEE*(Ct[i]+1),D=[b,E],e.next=17,Jt({client:s,network:o,assetIDs:[d,f,m]});case 17:if(!((S=e.sent).length>0)){e.next=23;break}return e.next=21,qt({client:s,initiatorAddr:r,assetIDs:S,routerAppID:_});case 21:O=e.sent,D.unshift(O);case 23:return N=t.assignGroupID(D),e.abrupt("return",N.map((function(t){return{txn:t,signers:[r]}})));case 25:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Jt(t){return Yt.apply(this,arguments)}function Yt(){return(Yt=o(a().mark((function e(n){var r,s,o,i,u,c;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,o=n.assetIDs,i=t.getApplicationAddress(Vt(s)),e.next=4,r.accountInformation(i).do();case 4:return u=e.sent,c=u.assets.map((function(t){return t["asset-id"]})),e.abrupt("return",o.filter((function(t){return t!==j&&!c.includes(t)})));case 7:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Kt(t){return Ht.apply(this,arguments)}function Ht(){return(Ht=o(a().mark((function t(e){var n,r,s,o,i,u,c,p;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.amount,r=e.assetInID,s=e.assetOutID,o=e.swapType,i=e.network,u={asset_in_id:String(r),asset_out_id:String(s),swap_type:o,amount:String(n)},t.next=4,fetch("".concat(M[i].v1,"/swap-router/quotes/"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}).catch((function(){throw new Error("Network error")}));case 4:return c=t.sent,t.next=7,c.json();case 7:if(p=t.sent,c.ok){t.next=14;break}if(a=p,!Boolean(a)||void 0===a.fallback_message){t.next=13;break}throw new E(p.type,p.fallback_message);case 13:throw new E(b.UnknownError,"There was an error while getting a quote from Swap Router");case 14:if(!(p.route.length<2)){t.next=16;break}throw new E(b.SwapRouterNoRouteError,"Swap router couldn't find a route for this swap.");case 16:return t.abrupt("return",p);case 17:case"end":return t.stop()}var a}),t)})))).apply(this,arguments)}var Zt=function(t){return t.Direct="direct",t.Router="router",t}({}),$t=4*t.ALGORAND_MIN_TX_FEE;function te(e){return(kt[e]+Lt)*t.ALGORAND_MIN_TX_FEE}function ee(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Nt;return Math.ceil(1/t)}function ne(t){return t1&&void 0!==arguments[1]?arguments[1]:Nt)}function re(e){return(kt[e]+1)*t.ALGORAND_MIN_TX_FEE}function ae(t){var e=t.assetIn,n=t.assetOut;return pt(n.decimals,Number(n.amount))/pt(e.decimals,Number(e.amount))}function se(t){var e=t.inputSupply,n=t.outputSupply,r=t.assetIn,a=t.assetOut,s=ae({assetIn:r,assetOut:a}),o=pt(a.decimals,Number(n))/pt(r.decimals,Number(e));return lt({decimalPlaces:5},Math.abs(s/o-1))}function oe(t){if(t.type===Zt.Router){var e=Qt(t.data.route);return{id:H(e.asset),amount:Number(e.amount)}}return{id:t.data.quote.assetInID,amount:t.data.quote.assetInAmount}}function ie(t){if(t.type===Zt.Router){var e=Xt(t.data.route);return{id:H(e.asset),amount:Number(e.amount)}}return{id:t.data.quote.assetOutID,amount:t.data.quote.assetOutAmount}}function ue(t){return t.type===Zt.Direct?t.data.pool.contractVersion:C.V2}function ce(t){return t.type===Zt.Direct?t.data.quote.rate:jt(t.data.route)}function pe(t){for(var e=t[0],n=ce(e),r=1;rn&&(e=a,n=s)}return e}function le(t){return t instanceof E&&[b.SwapRouterInsufficientReservesError,b.SwapRouterLowSwapAmountError,b.OutputAmountExceedsAvailableLiquidityError,b.LowSwapAmountError].includes(t.type)}var de={type:"logicsig",logic:{bytecode:"BCAIAQCBgICAgICAgPABgICAgICAgIDwAQMEBQYlJA1EMQkyAxJEMRUyAxJEMSAyAxJEMgQiDUQzAQAxABJEMwEQIQcSRDMBGIGCgICAgICAgPABEkQzARkiEjMBGyEEEhA3ARoAgAlib290c3RyYXASEEAAXDMBGSMSRDMBG4ECEjcBGgCABHN3YXASEEACOzMBGyISRDcBGgCABG1pbnQSQAE7NwEaAIAEYnVybhJAAZg3ARoAgAZyZWRlZW0SQAJbNwEaAIAEZmVlcxJAAnkAIQYhBSQjEk0yBBJENwEaARclEjcBGgIXJBIQRDMCADEAEkQzAhAhBBJEMwIhIxJEMwIiIxwSRDMCIyEHEkQzAiQjEkQzAiWACFRNUE9PTDExEkQzAiZRAA+AD1RpbnltYW5Qb29sMS4xIBJEMwIngBNodHRwczovL3RpbnltYW4ub3JnEkQzAikyAxJEMwIqMgMSRDMCKzIDEkQzAiwyAxJEMwMAMQASRDMDECEFEkQzAxElEkQzAxQxABJEMwMSIxJEJCMTQAAQMwEBMwIBCDMDAQg1AUIBsTMEADEAEkQzBBAhBRJEMwQRJBJEMwQUMQASRDMEEiMSRDMBATMCAQgzAwEIMwQBCDUBQgF8MgQhBhJENwEcATEAE0Q3ARwBMwQUEkQzAgAxABNEMwIUMQASRDMDADMCABJEMwIRJRJEMwMUMwMHMwMQIhJNMQASRDMDESMzAxAiEk0kEkQzBAAxABJEMwQUMwIAEkQzAQEzBAEINQFCAREyBCEGEkQ3ARwBMQATRDcBHAEzAhQSRDMDFDMDBzMDECISTTcBHAESRDMCADEAEkQzAhQzBAASRDMCESUSRDMDADEAEkQzAxQzAwczAxAiEk0zBAASRDMDESMzAxAiEk0kEkQzBAAxABNEMwQUMQASRDMBATMCAQgzAwEINQFCAJAyBCEFEkQ3ARwBMQATRDMCADcBHAESRDMCADEAE0QzAwAxABJEMwIUMwIHMwIQIhJNMQASRDMDFDMDBzMDECISTTMCABJEMwEBMwMBCDUBQgA+MgQhBBJENwEcATEAE0QzAhQzAgczAhAiEk03ARwBEkQzAQEzAgEINQFCABIyBCEEEkQzAQEzAgEINQFCAAAzAAAxABNEMwAHMQASRDMACDQBD0M=",address:"ABUKAXTANWR6K6ZYV75DWJEPVWWOU6SFUVRI6QHO44E4SIDLHBTD2CZ64A",size:881,variables:[{name:"TMPL_ASSET_ID_1",type:"int",index:15,length:10},{name:"TMPL_ASSET_ID_2",type:"int",index:5,length:10},{name:"TMPL_VALIDATOR_APP_ID",type:"int",index:74,length:10}],source:"https://github.com/tinymanorg/tinyman-contracts-v1/tree/dc9ab40c58b85c15d58f63a1507e18be76720dbb/contracts/pool_logicsig.teal.tmpl"},name:"pool_logicsig"},fe={type:"app",global_state_schema:{num_uints:0,num_byte_slices:0},local_state_schema:{num_uints:16,num_byte_slices:0},name:"validator_app"},me=c((function t(e){i(this,t),this.schema={numLocalInts:e.local_state_schema.num_uints,numLocalByteSlices:e.local_state_schema.num_byte_slices,numGlobalInts:e.global_state_schema.num_uints,numGlobalByteSlices:e.global_state_schema.num_byte_slices}})),ge=new(function(n){l(a,me);var r=x(a);function a(t,e){var n;return i(this,a),(n=r.call(this,t)).poolLogicSigContractTemplate=e.logic.bytecode,n.templateVariables=e.logic.variables,n}return c(a,[{key:"generateLogicSigAccountForPool",value:function(n){if(n.asset1ID===n.asset2ID)throw new Error("Assets are the same");var r=wt(n.network,C.V1_1),a=h(Y(n.asset1ID,n.asset2ID),2),s=a[0],o=a[1],i=Array.from(e.toByteArray(this.poolLogicSigContractTemplate)),u={asset_id_1:s,asset_id_2:o,validator_app_id:r},c=0;this.templateVariables.sort((function(t,e){return t.index-e.index}));for(var p=0;p2&&void 0!==arguments[2]?arguments[2]:t.IntDecoding.DEFAULT;return new Promise(function(){var t=o(a().mark((function t(o,i){var u;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.prev=0,t.next=3,e.accountInformation(n).setIntDecoding(s).do();case 3:u=t.sent,o(r(r({},u),{},{minimum_required_balance:ye(u)})),t.next=10;break;case 7:t.prev=7,t.t0=t.catch(0),i(new Error(t.t0.message||"Failed to fetch account information"));case 10:case"end":return t.stop()}}),t,null,[[0,7]])})));return function(e,n){return t.apply(this,arguments)}}())}function Te(t,e){var n=t["apps-local-state"].find((function(t){return t.id===e}));return n?Z({stateArray:n["key-value"],shouldDecodeKeys:!0}):null}function ye(t){var e=t["apps-total-schema"];return S+O*(t.assets||[]).length+P*(t["created-apps"]||[]).length+N*(t["apps-local-state"]||[]).length+L*Number(e&&e["num-byte-slice"]||0)+R*Number(e&&e["num-uint"]||0)+k*(t["apps-total-extra-pages"]||0)}var we=ht("e");function _e(t){return be.apply(this,arguments)}function be(){return(be=o(a().mark((function n(r){var s,o,i,u,c,p,l,d,f,m,g,A,I,x,h,v,T,y,_,b,E;return a().wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return s=r.client,o=r.pool,i=r.accountAddr,n.next=3,s.accountInformation(i).setIntDecoding(t.IntDecoding.BIGINT).do();case 3:u=n.sent,c=u["apps-local-state"]||[],p=0n,l=0n,d=0n,f=o.account.address(),m=w(c),n.prev=10,m.s();case 12:if((g=m.n()).done){n.next=31;break}if((A=g.value).id==o.validatorAppID){n.next=16;break}return n.abrupt("continue",29);case 16:if(I=A["key-value"]){n.next=19;break}return n.abrupt("break",31);case 19:x=Z({stateArray:I}),h=e.fromByteArray($([t.decodeAddress(f).publicKey,we,t.encodeUint64(o.asset1ID)])),v=e.fromByteArray($([t.decodeAddress(f).publicKey,we,t.encodeUint64(o.asset2ID)])),T=e.fromByteArray($([t.decodeAddress(f).publicKey,we,t.encodeUint64(o.poolTokenID)])),y=x[h],_=x[v],b=x[T],"bigint"==typeof y&&(p=y),"bigint"==typeof _&&(l=_),"bigint"==typeof b&&(d=b);case 29:n.next=12;break;case 31:n.next=36;break;case 33:n.prev=33,n.t0=n.catch(10),m.e(n.t0);case 36:return n.prev=36,m.f(),n.finish(36);case 39:if(!((E={excessAsset1:p,excessAsset2:l,excessPoolTokens:d}).excessAsset1<0n||E.excessAsset2<0n||E.excessPoolTokens<0n)){n.next=42;break}throw new Error("Invalid account excess: ".concat(E));case 42:return n.abrupt("return",E);case 43:case"end":return n.stop()}}),n,null,[[10,33,36,39]])})))).apply(this,arguments)}function Ee(){return(Ee=o(a().mark((function n(r){var s,o,i,u,c,p,l,d,f,m,g,A,I,x,v;return a().wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return s=r.client,o=r.accountAddr,i=r.validatorAppID,n.next=3,s.accountInformation(o).setIntDecoding(t.IntDecoding.BIGINT).do();case 3:if(u=n.sent,c=u["apps-local-state"]||[],p=c.find((function(t){return t.id==i})),l=[],p&&p["key-value"])for(d=Z({stateArray:p["key-value"]}),f=0,m=Object.entries(d);fke)){n.next=48;break}throw new Error("Issued liquidity value is out of the expected range ([0n, ".concat(ke,"]): ").concat(k.issuedLiquidity));case 48:return n.abrupt("return",k);case 49:case"end":return n.stop()}}),n,null,[[8,31,34,37]])})))).apply(this,arguments)}function Be(){return Be=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d=arguments;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(n=e.client,r=e.address,s=e.network,!(o=d.length>1&&void 0!==d[1]?d[1]:{})[r]){t.next=4;break}return t.abrupt("return",o[r]);case 4:return t.next=6,ve(n,r);case 6:return i=t.sent,u=Te(i,wt(s,C.V1_1)),c=null,u&&(l=i["created-assets"][0],p=l.index,c={asset1ID:u[Oe[C.V1_1].asset1],asset2ID:u[Oe[C.V1_1].asset2],poolTokenID:p},o[r]=c),t.abrupt("return",c);case 11:case"end":return t.stop()}}),t)}))),Be.apply(this,arguments)}var Me=Object.freeze({__proto__:null,getPoolAssets:function(t){return Be.apply(this,arguments)},getPoolInfo:Le,getPoolReserves:function(t,e){return Fe.apply(this,arguments)}});function Ce(t){return je.apply(this,arguments)}function je(){return(je=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d,f,m;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.network,s=e.asset1ID,o=e.asset2ID,i=he(C.V2),u=i.generateLogicSigAccountForPool(e),c=wt(r,C.V2),p=u.address(),l=Y(s,o),t.next=8,ve(n,p);case 8:return d=t.sent,f=Te(d,c),m={account:u,validatorAppID:c,asset1ID:l[0],asset2ID:l[1],status:f?Se.READY:Se.NOT_CREATED,contractVersion:C.V2},f&&(m.asset1ProtocolFees=BigInt(f[Oe.v2.asset1ProtocolFees]),m.asset2ProtocolFees=BigInt(f[Oe.v2.asset2ProtocolFees]),m.asset1Reserves=BigInt(f[Oe.v2.asset1Reserves]),m.asset2Reserves=BigInt(f[Oe.v2.asset2Reserves]),m.issuedPoolTokens=BigInt(f[Oe.v2.issuedPoolTokens]),m.cumulativePriceUpdateTimeStamp=Number(f[Oe.v2.cumulativePriceUpdateTimeStamp]),m.protocolFeeRatio=Number(f[Oe.v2.protocolFeeRatio]),m.totalFeeShare=BigInt(f[Oe.v2.totalFeeShare]),m.poolTokenID=Number(f[Oe.v2.poolTokenID]),m.asset1ID=Number(f[Oe.v2.asset1]),m.asset2ID=Number(f[Oe.v2.asset2])),t.abrupt("return",m);case 13:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Ve(){return(Ve=o(a().mark((function t(e,n){var r,s,o;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,ve(e,n.account.address());case 2:return r=t.sent,s=Te(r,n.validatorAppID),o={asset1:0n,asset2:0n,issuedLiquidity:0n,round:r.round},s&&(o.asset1=BigInt(s[Oe.v2.asset1Reserves]),o.asset2=BigInt(s[Oe.v2.asset2Reserves]),o.issuedLiquidity=BigInt(s[Oe.v2.issuedPoolTokens])),t.abrupt("return",o);case 7:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Xe(){return(Xe=o(a().mark((function t(e){var n,r,s,o,i,u;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.address,s=e.network,t.next=3,ve(n,r);case 3:return o=t.sent,i=Te(o,wt(s,C.V2)),u=null,i&&(u={asset1ID:i[Oe[C.V2].asset1],asset2ID:i[Oe[C.V2].asset2],poolTokenID:i[Oe[C.V2].poolTokenID]}),t.abrupt("return",u);case 8:case"end":return t.stop()}}),t)})))).apply(this,arguments)}var Qe=Object.freeze({__proto__:null,getPoolAssets:function(t){return Xe.apply(this,arguments)},getPoolInfo:Ce,getPoolReserves:function(t,e){return Ve.apply(this,arguments)}});function Ue(t){return Boolean(t&&!(t.asset1+t.asset2))}var qe,Ge=Object.freeze({__proto__:null,getPoolPairRatio:function(t,e){var n=Ue(e),r=null;return e&&!n&&e.asset1&&e.asset2&&"number"==typeof t.asset2&&"number"==typeof t.asset1&&(r=pt(t.asset1,e.asset1)/pt(t.asset2,e.asset2)),r},getPoolShare:function(t,e){var n=Number(e)/Number(t);return Number.isFinite(n)||(n=0),n},getPoolsForPair:function(t){return Promise.all([Le(t),Ce(t)])},isPoolEmpty:Ue,isPoolNotCreated:function(t){return(null==t?void 0:t.status)===Se.NOT_CREATED},isPoolReady:function(t){return(null==t?void 0:t.status)===Se.READY}}),We=r((p(qe={},C.V1_1,r(r({},Me),Ge)),p(qe,C.V2,r(r({},Qe),Ge)),qe),Ge),ze=function(t){return t[t.FUNDING_TXN=0]="FUNDING_TXN",t[t.VALIDATOR_APP_CALL=1]="VALIDATOR_APP_CALL",t[t.POOL_TOKEN_CREATE=2]="POOL_TOKEN_CREATE",t[t.ASSET1_OPT_IN=3]="ASSET1_OPT_IN",t[t.ASSET2_OPT_IN=4]="ASSET2_OPT_IN",t}({}),Je={ASA_ALGO:96e4,ASA_ASA:859e3};function Ye(){return(Ye=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,v,T,y,w,_,b,E,D,S,O;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,o=n.asset_1,i=n.asset_2,u=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return c=e.sent,p=J(o,i),l=h(p,2),d=l[0],f=d.id,m=d.unit_name,g=l[1],A=g.id,I=g.unit_name,x=K(A),v=wt(s,C.V1_1),T=ge.generateLogicSigAccountForPool({network:s,asset1ID:f,asset2ID:A}),y=T.address(),w=t.makeApplicationOptInTxnFromObject({from:y,appIndex:v,note:Tt.getAppCallTxnNoteWithClientName(C.V1_1),appArgs:[ht("bootstrap"),t.encodeUint64(f),t.encodeUint64(A)],foreignAssets:x?[f]:[A],suggestedParams:c}),_=t.makeAssetCreateTxnWithSuggestedParamsFromObject({from:y,total:0xffffffffffffffffn,decimals:6,defaultFrozen:!1,unitName:X.V1_1,assetName:"TinymanPool1.1 ".concat(m,"-").concat(I),assetURL:"https://tinyman.org",suggestedParams:c}),b=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:y,to:y,assetIndex:f,amount:0,suggestedParams:c}),E=t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:y,amount:Ke(x),suggestedParams:c}),(D=[])[ze.FUNDING_TXN]=E,D[ze.VALIDATOR_APP_CALL]=w,D[ze.POOL_TOKEN_CREATE]=_,D[ze.ASSET1_OPT_IN]=b,x||(D[ze.ASSET2_OPT_IN]=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:y,to:y,assetIndex:A,amount:0,suggestedParams:c})),S=t.assignGroupID(D),O=[{txn:S[ze.FUNDING_TXN],signers:[u]},{txn:S[ze.VALIDATOR_APP_CALL],signers:[y]},{txn:S[ze.POOL_TOKEN_CREATE],signers:[y]},{txn:S[ze.ASSET1_OPT_IN],signers:[y]}],S[ze.ASSET2_OPT_IN]&&O.push({txn:S[ze.ASSET2_OPT_IN],signers:[y]}),e.abrupt("return",O);case 23:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Ke(t){return t?Je.ASA_ALGO:Je.ASA_ASA}function He(){return(He=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.txGroup,s=n.network,o=n.initiatorSigner,i=n.asset1ID,u=n.asset2ID,e.next=3,o([r]);case 3:return c=e.sent,p=h(c,1),l=p[0],d=Y(i,u),f=h(d,2),m=f[0],g=f[1],A=ge.generateLogicSigAccountForPool({network:s,asset1ID:m,asset2ID:g}),I=[],x=r.map((function(e,n){if(n===ze.FUNDING_TXN)return I.push(e.txn.txID().toString()),l;var r=t.signLogicSigTransactionObject(e.txn,A),a=r.txID,s=r.blob;return I.push(a),s})),e.abrupt("return",{signedTxns:x,txnIDs:I});case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Ze(t){return $e.apply(this,arguments)}function $e(){return($e=o(a().mark((function t(e){var n,r,s,o,i;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.signedTxns,s=e.txnIDs,t.prev=1,t.next=4,n.sendRawTransaction(r).do();case 4:return t.next=6,it(n,s[ze.POOL_TOKEN_CREATE]);case 6:if(o=t.sent,"number"==typeof(i=o["asset-index"])){t.next=10;break}throw new Error("Generated ID is not valid: got ".concat(i));case 10:return t.abrupt("return",{poolTokenID:i});case 13:throw t.prev=13,t.t0=t.catch(1),new W(t.t0,"We encountered something unexpected while bootstraping the pool. Try again later.");case 16:case"end":return t.stop()}}),t,null,[[1,13]])})))).apply(this,arguments)}function tn(){return(tn=o(a().mark((function t(e){var n,r,s,o,i,u,c;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.network,s=e.pool,o=s.asset1ID,i=s.asset2ID,u=e.signedTxns,c=e.txnIDs,t.next=3,Ze({client:n,signedTxns:u,txnIDs:c});case 3:return t.abrupt("return",We.v1_1.getPoolInfo({client:n,network:r,asset1ID:o,asset2ID:i}));case 4:case"end":return t.stop()}}),t)})))).apply(this,arguments)}var en={generateTxns:function(t){return Ye.apply(this,arguments)},signTxns:function(t){return He.apply(this,arguments)},execute:function(t){return tn.apply(this,arguments)},getBootstrapFundingTxnAmount:Ke};var nn=function(t){return t[t.FUNDING_TXN=0]="FUNDING_TXN",t[t.VALIDATOR_APP_CALL=1]="VALIDATOR_APP_CALL",t}({}),rn={ASA_ALGO:5,ASA_ASA:6};function an(t,e){return sn.apply(this,arguments)}function sn(){return(sn=o(a().mark((function e(n,r){var s,o,i;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!(o=null===(s=r.find((function(t){return"appl"===t.txn.type})))||void 0===s?void 0:s.txn.txID())){e.next=7;break}return e.next=4,t.waitForConfirmation(n,o,B);case 4:e.t0=e.sent,e.next=8;break;case 7:e.t0=void 0;case 8:return i=e.t0,e.abrupt("return",i);case 10:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function on(t,e){return un.apply(this,arguments)}function un(){return(un=o(a().mark((function t(e,n){var r;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,an(e,n);case 2:return r=t.sent,t.abrupt("return",null==r?void 0:r["inner-txns"]);case 4:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function cn(t,e){return pn.apply(this,arguments)}function pn(){return(pn=o(a().mark((function e(n,r){var s,o;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,on(n,r);case 2:return s=e.sent,a=r[0].txn,o=t.encodeAddress(a.from.publicKey),e.abrupt("return",null==s?void 0:s.reduce((function(e,n){var r=e,a=n.txn.txn;return a.type===t.TransactionType.axfer&&t.encodeAddress(a.arcv)===o?r.push({id:a.xaid,amount:a.aamt}):a.type===t.TransactionType.pay&&t.encodeAddress(a.rcv)===o&&r.push({id:j,amount:a.amt}),r}),[]));case 5:case"end":return e.stop()}var a}),e)})))).apply(this,arguments)}function ln(){return(ln=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,v,T,y,w,_;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,o=n.asset_1,i=n.asset_2,u=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return c=e.sent,p=wt(s,C.V2),l=t.getApplicationAddress(p),d=J(o,i),f=h(d,2),m=f[0].id,g=f[1].id,e.next=9,We.v2.getPoolInfo({client:r,network:s,asset1ID:m,asset2ID:g});case 9:if(e.sent.status!==Se.READY){e.next=12;break}throw new Error("Pool for ".concat(o.unit_name,"-").concat(i.unit_name," already exists"));case 12:return A=xe.generateLogicSigAccountForPool({network:s,asset1ID:m,asset2ID:g}),I=A.address(),x=K(g),(v=t.makeApplicationOptInTxnFromObject({from:I,appIndex:p,appArgs:[ht("bootstrap")],note:Tt.getAppCallTxnNoteWithClientName(C.V2),foreignAssets:[m,g],rekeyTo:l,suggestedParams:c})).fee=fn(x),T=t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:I,amount:dn(x),suggestedParams:c}),(y=[])[nn.FUNDING_TXN]=T,y[nn.VALIDATOR_APP_CALL]=v,w=t.assignGroupID(y),(_=[])[nn.FUNDING_TXN]={txn:w[nn.FUNDING_TXN],signers:[u]},_[nn.VALIDATOR_APP_CALL]={txn:w[nn.VALIDATOR_APP_CALL],signers:[I]},e.abrupt("return",_);case 26:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function dn(t){return function(t,e){var n=he(t).schema,r=n.numLocalInts,a=n.numLocalByteSlices,s=S+O+O+N+R*r+L*a;return e||(s+=O),s}(C.V2,t)+fn(t)+O}function fn(e){return((e?rn.ASA_ALGO:rn.ASA_ASA)+1)*t.ALGORAND_MIN_TX_FEE}function mn(){return(mn=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.txGroup,s=n.network,o=n.initiatorSigner,i=n.asset1ID,u=n.asset2ID,e.next=3,o([r]);case 3:return c=e.sent,p=h(c,1),l=p[0],d=Y(i,u),f=h(d,2),m=f[0],g=f[1],A=xe.generateLogicSigAccountForPool({network:s,asset1ID:m,asset2ID:g}),I=[],x=r.map((function(e,n){if(n===nn.FUNDING_TXN)return I.push(e.txn.txID().toString()),l;var r=t.signLogicSigTransactionObject(e.txn,A),a=r.txID,s=r.blob;return I.push(a),s})),e.abrupt("return",{signedTxns:x,txnIDs:I});case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function gn(){return(gn=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d,f;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.network,s=e.pool,o=s.asset1ID,i=s.asset2ID,u=e.txGroup,c=e.signedTxns,t.prev=1,t.next=4,n.sendRawTransaction(c).do();case 4:return t.next=6,an(n,u);case 6:if(t.t1=p=t.sent,t.t0=null===t.t1,t.t0){t.next=10;break}t.t0=void 0===p;case 10:if(!t.t0){t.next=14;break}t.t2=void 0,t.next=15;break;case 14:t.t2=null===(l=p["local-state-delta"][0].delta)||void 0===l||null===(d=l.find((function(t){return t.key===btoa(Oe.v2.poolTokenID)})))||void 0===d?void 0:d.value.uint;case 15:if("number"==typeof(f=t.t2)){t.next=18;break}throw new Error("Generated ID is not valid: got ".concat(f));case 18:return t.abrupt("return",We.v2.getPoolInfo({client:n,network:r,asset1ID:o,asset2ID:i}));case 21:throw t.prev=21,t.t3=t.catch(1),new W(t.t3,"We encountered something unexpected while bootstraping the pool. Try again later.");case 24:case"end":return t.stop()}}),t,null,[[1,21]])})))).apply(this,arguments)}var An,In={generateTxns:function(t){return ln.apply(this,arguments)},signTxns:function(t){return mn.apply(this,arguments)},execute:function(t){return gn.apply(this,arguments)},getBootstrapFundingTxnAmount:dn,getTotalCost:function(e){return t.ALGORAND_MIN_TX_FEE+dn(e)}};var xn,hn,vn,Tn,yn=(p(An={},C.V1_1,en),p(An,C.V2,In),p(An,"generateTxns",(function(t){return t.contractVersion===C.V1_1?en.generateTxns(t):In.generateTxns(t)})),p(An,"signTxns",(function(t){return t.contractVersion===C.V1_1?en.signTxns(t):In.signTxns(t)})),p(An,"execute",(function(t){return t.contractVersion===C.V1_1?en.execute(t):In.execute(t)})),p(An,"calculateBootstrapFundingTxnAmount",(function(t){var e=t.contractVersion,n=t.isAlgoPool;return e===C.V1_1?en.getBootstrapFundingTxnAmount(n):In.getBootstrapFundingTxnAmount(n)})),An),wn=function(t){return t[t.FEE_TXN=0]="FEE_TXN",t[t.VALIDATOR_APP_CALL_TXN=1]="VALIDATOR_APP_CALL_TXN",t[t.ASSET1_IN_TXN=2]="ASSET1_IN_TXN",t[t.ASSET2_IN_TXN=3]="ASSET2_IN_TXN",t[t.LIQUDITY_OUT_TXN=4]="LIQUDITY_OUT_TXN",t}({}),_n=5*t.ALGORAND_MIN_TX_FEE,bn=function(t){return t.SINGLE="single",t.FLEXIBLE="flexible",t.INITIAL="initial",t}({}),En=(p(xn={},bn.FLEXIBLE,{ASSET1_IN_TXN:0,ASSET2_IN_TXN:1,VALIDATOR_APP_CALL_TXN:2}),p(xn,bn.SINGLE,{ASSET_IN_TXN:0,VALIDATOR_APP_CALL_TXN:1}),p(xn,bn.INITIAL,{ASSET1_IN_TXN:0,ASSET2_IN_TXN:1,VALIDATOR_APP_CALL_TXN:2}),xn),Dn=(p(hn={},bn.INITIAL,1),p(hn,bn.SINGLE,2),p(hn,bn.FLEXIBLE,2),hn),Sn=(p(vn={},bn.INITIAL,3),p(vn,bn.FLEXIBLE,3),p(vn,bn.SINGLE,2),vn);function On(t){var e,n,r,a=t.reserves,s=t.totalFeeShare,o=t.asset1,i=t.asset2,u=a.asset1*a.asset2,c=a.asset1+BigInt(o.amount),p=a.asset2+BigInt(i.amount),l=c*p,d=BigInt(parseInt(String(Math.sqrt(Number(l*a.issuedLiquidity*a.issuedLiquidity/u))))),f=d-a.issuedLiquidity,m=f*c/d,g=f*p/d,A=BigInt(o.amount)-m,I=BigInt(i.amount)-g;if(A>I){var x=A;r=Pn(x,s),e={id:o.id,amount:x+r,decimals:o.decimals,reserves:a.asset1},n={id:i.id,amount:BigInt(Math.abs(Math.min(Number(I),0))),decimals:i.decimals,reserves:a.asset2},f-=r*d/(c*BigInt(2))}else{var h=I;r=Pn(h,s),e={id:i.id,amount:h+r,decimals:i.decimals,reserves:a.asset2},n={id:o.id,amount:BigInt(Math.abs(Math.min(Number(A),0))),decimals:o.decimals,reserves:a.asset1},f-=r*d/(p*BigInt(2))}return{poolTokenOutAmount:f,internalSwapQuote:{assetIn:e,assetOut:n,swapFees:r,priceImpact:se({inputSupply:e.reserves,outputSupply:n.reserves,assetIn:e,assetOut:n})}}}function Nn(t,e){if(!t.amount||!e.amount)throw new Error("Both assets are required for the initial add liquidity");return BigInt(Math.floor(Math.abs(Math.sqrt(Number(t.amount)*Number(e.amount))-Ne)))}function Pn(t,e){return t*BigInt(e)/(BigInt(1e4)-BigInt(e))}function kn(e){return(Dn[e]+1)*t.ALGORAND_MIN_TX_FEE}var Ln=ht("add_liquidity"),Rn=(p(Tn={},C.V1_1,[ht("mint")]),p(Tn,C.V2,{INITIAL_LIQUIDITY:[ht("add_initial_liquidity")],SINGLE_ASSET_MODE:[Ln,ht("single")],FLEXIBLE_MODE:[Ln,ht("flexible")]}),Tn);function Fn(){return(Fn=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,h;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.network,o=n.poolAddress,i=n.asset1In,u=n.asset2In,c=n.poolTokenOut,p=n.slippage,l=n.initiatorAddr,d=ct("negative",p,c.amount),e.next=4,r.getTransactionParams().do();case 4:return f=e.sent,m=t.makeApplicationNoOpTxnFromObject({from:o,appIndex:wt(s,C.V1_1),appArgs:Rn.v1_1,accounts:[l],note:Tt.getAppCallTxnNoteWithClientName(C.V1_1),foreignAssets:u.id==j?[i.id,c.id]:[i.id,u.id,c.id],suggestedParams:f}),g=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:l,to:o,assetIndex:i.id,amount:i.amount,suggestedParams:f}),A=u.id===j?t.makePaymentTxnWithSuggestedParamsFromObject({from:l,to:o,amount:u.amount,suggestedParams:f}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:l,to:o,assetIndex:u.id,amount:u.amount,suggestedParams:f}),I=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:o,to:l,assetIndex:c.id,amount:d,suggestedParams:f}),x=t.makePaymentTxnWithSuggestedParamsFromObject({from:l,to:o,amount:m.fee+I.fee,note:D,suggestedParams:f}),h=t.assignGroupID([x,m,g,A,I]),e.abrupt("return",[{txn:h[0],signers:[l]},{txn:h[1],signers:[o]},{txn:h[2],signers:[l]},{txn:h[3],signers:[l]},{txn:h[4],signers:[o]}]);case 12:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Bn(){return(Bn=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.pool,s=n.txGroup,o=n.initiatorSigner,i=r.account,e.next=4,o([s]);case 4:return u=e.sent,c=h(u,3),p=c[0],l=c[1],d=c[2],f=s.map((function(e,n){return n===wn.FEE_TXN?p:n===wn.ASSET1_IN_TXN?l:n===wn.ASSET2_IN_TXN?d:t.signLogicSigTransactionObject(e.txn,i).blob})),e.abrupt("return",f);case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Mn(){return(Mn=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,v;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.txGroup,o=e.signedTxns,i=e.initiatorAddr,t.prev=1,u=BigInt(s[wn.LIQUDITY_OUT_TXN].txn.amount),t.next=5,_e({client:n,pool:r,accountAddr:i});case 5:return c=t.sent,t.next=8,mt(n,[o]);case 8:return p=t.sent,l=h(p,1),d=l[0],f=d.confirmedRound,m=d.txnID,g=At(s),A=It(s),t.next=17,_e({client:n,pool:r,accountAddr:i});case 17:return I=t.sent,(x=I.excessPoolTokens-c.excessPoolTokens)<0n&&(x=0n),t.abrupt("return",{round:f,fees:g,poolTokenID:r.poolTokenID,poolTokenOut:u+x,excessAmount:{excessAmountForAddingLiquidity:x,totalExcessAmount:I.excessPoolTokens},txnID:m,groupID:A});case 23:throw t.prev=23,t.t0=t.catch(1),"SlippageTolerance"===(v=new W(t.t0,"We encountered something unexpected while adding liquidity. Try again later.")).type&&v.setMessage("Adding liquidity failed due to too much slippage in the price. Please adjust the slippage tolerance and try again."),v;case 28:case"end":return t.stop()}}),t,null,[[1,23]])})))).apply(this,arguments)}var Cn=Object.freeze({__proto__:null,execute:function(t){return Mn.apply(this,arguments)},generateTxns:function(t){return Fn.apply(this,arguments)},getQuote:function(t){var e=t.pool,n=t.reserves,r=t.asset1In,a=t.asset2In;if(0n===n.issuedLiquidity){var s=BigInt(Math.floor(Math.sqrt(Number(r)*Number(a))));if(s<=BigInt(F))throw new Error("Initial liquidity amount is too small. The amount must be greater than ".concat(F,", this quote is for ").concat(s,"."));return{round:n.round,asset1ID:e.asset1ID,asset1In:BigInt(r),asset2ID:e.asset2ID,asset2In:BigInt(a),poolTokenID:e.poolTokenID,poolTokenOut:s-BigInt(F),share:1}}var o=BigInt(r)*n.issuedLiquidity/n.asset1,i=BigInt(a)*n.issuedLiquidity/n.asset2,u=oo)throw new E(b.OutputAmountExceedsAvailableLiquidityError,"Output amount exceeds available liquidity.");if(ne(Number(e)))throw new E(b.LowSwapAmountError,"Swap amount is too low.");return{assetInID:i,assetInAmount:l,assetOutID:c,assetOutAmount:m,swapFee:Number(g),rate:pt(p,Number(m))/pt(u,Number(l)),priceImpact:A}}function lr(t){var e=t.amount,n=t.assetIn,r=t.assetOut,a=t.pool;if(!a||!We.isPoolReady(a))throw new E(b.NoAvailablePoolError,"There is not an available pool for this asset pair");var s,o,i=n.id,u=n.decimals,c=r.id,p=r.decimals,l=BigInt(e),d=a.totalFeeShare;if(c===a.asset1ID)s=a.asset2Reserves,o=a.asset1Reserves;else{if(c!==a.asset2ID)throw new E(b.AssetDoesNotBelongToPoolError,"Output asset (#".concat(c,") doesn't belong to the pool ").concat(a.account.address(),"."));s=a.asset1Reserves,o=a.asset2Reserves}var f=function(t){var e=t.inputSupply,n=t.outputSupply,r=t.swapOutputAmount,a=t.totalFeeShare,s=t.decimals,o=function(t){var e=t.inputSupply,n=t.outputSupply,r=t.outputAmount,a=e*n,s=BigInt(a/(n-r))-e;return s+=BigInt(1),s}({inputSupply:e,outputSupply:n,outputAmount:r}),i=function(t){var e=t.swapAmount,n=t.totalFeeShare,r=Math.floor(Number(e*BigInt(1e4)/(BigInt(1e4)-BigInt(n)))),a=BigInt(r)-e;return a}({swapAmount:o,totalFeeShare:a}),u=o+i,c=se({inputSupply:e,outputSupply:n,assetIn:{amount:u,decimals:s.assetIn},assetOut:{amount:r,decimals:s.assetOut}});return{swapInputAmount:u,totalFeeAmount:i,priceImpact:c}}({inputSupply:s,outputSupply:o,swapOutputAmount:l,totalFeeShare:d,decimals:{assetIn:u,assetOut:p}}),m=f.swapInputAmount,g=f.totalFeeAmount,A=f.priceImpact;if(l>o)throw new E(b.OutputAmountExceedsAvailableLiquidityError,"Output amount exceeds available liquidity.");if(ne(Number(m)))throw new E(b.LowSwapAmountError,"Swap amount is too low.");return{type:Zt.Direct,data:{pool:a,quote:{assetInID:i,assetInAmount:m,assetOutID:c,assetOutAmount:l,swapFee:Number(g),rate:pt(p,Number(l))/pt(u,Number(m)),priceImpact:A}}}}function dr(t){return fr.apply(this,arguments)}function fr(){return(fr=o(a().mark((function t(e){var n,r,s,o,i,u,c,p;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.amount,r=e.assetIn,s=e.assetOut,o=e.isSwapRouterEnabled,i=e.network,u=e.pool,c=[],u?c.push(new Promise((function(t,e){try{var a=pr({amount:n,assetIn:r,assetOut:s,pool:u});t({type:Zt.Direct,data:{pool:u,quote:a}})}catch(t){e(t)}}))):c.push(Promise.reject(new E(b.NoAvailablePoolError,"There is not an available pool for this asset pair"))),o&&c.push(Kt({amount:n,assetInID:r.id,assetOutID:s.id,swapType:Ot.FixedInput,network:i}).then((function(t){return{type:Zt.Router,data:t}}))),t.next=6,cr(c);case 6:return p=t.sent,t.abrupt("return",pe(p));case 8:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function mr(t){return gr.apply(this,arguments)}function gr(){return(gr=o(a().mark((function t(e){var n,r,s,o,i,u,c,p;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.amount,r=e.assetIn,s=e.assetOut,o=e.isSwapRouterEnabled,i=e.network,u=e.pool,c=[new Promise((function(t,e){try{t(lr({amount:n,assetIn:r,assetOut:s,pool:u}))}catch(t){e(t)}}))],o&&c.push(Kt({amount:n,assetInID:r.id,assetOutID:s.id,swapType:Ot.FixedOutput,network:i}).then((function(t){return{type:Zt.Router,data:t}}))),t.next=5,cr(c);case 5:return p=t.sent,t.abrupt("return",pe(p));case 7:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Ar(t){var e=t.inputSupply,n=t.outputSupply,r=t.swapInputAmount,a=t.totalFeeShare,s=t.decimals,o=BigInt(function(t){var e=t.inputAmount,n=t.totalFeeShare;return Math.floor(Number(e*BigInt(n))/1e4)}({inputAmount:r,totalFeeShare:a})),i=function(t){var e=t.inputSupply,n=t.outputSupply,r=t.swapAmount,a=e*n,s=n-BigInt(a/(e+BigInt(r)));return s-=BigInt(1)}({inputSupply:e,outputSupply:n,swapAmount:r-o});return{swapOutputAmount:i,totalFeeAmount:o,priceImpact:se({inputSupply:e,outputSupply:n,assetIn:{amount:r,decimals:s.assetIn},assetOut:{amount:i,decimals:s.assetOut}})}}var Ir={getQuote:function(t){return ur.apply(this,arguments)},getFixedInputSwapQuote:dr,getFixedInputDirectSwapQuote:pr,getFixedOutputDirectSwapQuote:lr,getFixedOutputSwapQuote:mr,generateTxns:function(t){return or.apply(this,arguments)},signTxns:function(t){var e=t.txGroup;return(0,t.initiatorSigner)([e])},execute:function(t){return ir.apply(this,arguments)},calculateFixedInputSwap:Ar};function xr(t,e){var n,r,a=BigInt(t),s=e.issuedLiquidity;return s>a+BigInt(Ne)?(n=a*e.asset1/s,r=a*e.asset2/s):(n=e.asset1,r=e.asset2),{asset1OutputAmount:n,asset2OutputAmount:r}}function hr(){return(hr=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.pool,o=n.poolTokenIn,i=n.initiatorAddr,u=n.minAsset1Amount,c=n.minAsset2Amount,p=n.slippage,e.next=3,r.getTransactionParams().do();case 3:if(l=e.sent,d=s.account.address(),f=s.poolTokenID){e.next=8;break}throw new Error("Pool token asset ID is missing");case 8:return m=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:i,to:d,assetIndex:f,amount:o,suggestedParams:l}),(g=t.makeApplicationNoOpTxnFromObject({from:i,appIndex:s.validatorAppID,note:Tt.getAppCallTxnNoteWithClientName(C.V2),appArgs:[tr,t.encodeUint64(ct("negative",p,u)),t.encodeUint64(ct("negative",p,c))],accounts:[d],foreignAssets:[s.asset1ID,s.asset2ID],suggestedParams:l})).fee=($n+1)*t.ALGORAND_MIN_TX_FEE,(A=[])[er.ASSET_TRANSFER_TXN]=m,A[er.APP_CALL_TXN]=g,I=t.assignGroupID(A),e.abrupt("return",[{txn:I[er.ASSET_TRANSFER_TXN],signers:[i]},{txn:I[er.APP_CALL_TXN],signers:[i]}]);case 16:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function vr(){return(vr=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,h,v,T,y;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.pool,o=n.initiatorAddr,i=n.poolTokenIn,u=n.outputAssetId,c=n.minOutputAssetAmount,p=n.slippage,e.next=3,r.getTransactionParams().do();case 3:if(l=e.sent,d=s.asset1ID,f=s.asset2ID,m=s.account.address(),g=s.poolTokenID){e.next=9;break}throw new Error("Pool token asset ID is missing");case 9:if(A=0,I=0,x=ct("negative",p,c),u!==d){e.next=17;break}A=x,I=0,e.next=23;break;case 17:if(u!==f){e.next=22;break}A=0,I=x,e.next=23;break;case 22:throw new Error("Invalid output asset id. It doesn't match with pool assets");case 23:return h=t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:o,to:m,assetIndex:g,amount:i,suggestedParams:l}),(v=t.makeApplicationNoOpTxnFromObject({from:o,appIndex:s.validatorAppID,note:Tt.getAppCallTxnNoteWithClientName(C.V2),appArgs:[tr,t.encodeUint64(A),t.encodeUint64(I)],accounts:[m],foreignAssets:[u],suggestedParams:l})).fee=($n+1)*t.ALGORAND_MIN_TX_FEE,(T=[])[er.ASSET_TRANSFER_TXN]=h,T[er.APP_CALL_TXN]=v,y=t.assignGroupID(T),e.abrupt("return",[{txn:y[er.ASSET_TRANSFER_TXN],signers:[o]},{txn:y[er.APP_CALL_TXN],signers:[o]}]);case 31:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Tr(){return(Tr=o(a().mark((function t(e){var n,r,s,o,i,u,c;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.txGroup,s=e.signedTxns,t.next=3,mt(n,[s]);case 3:return o=t.sent,i=h(o,1),u=i[0].txnID,t.prev=6,t.next=9,cn(n,r);case 9:c=t.sent,t.next=14;break;case 12:t.prev=12,t.t0=t.catch(6);case 14:return t.abrupt("return",{outputAssets:c,txnID:u});case 15:case"end":return t.stop()}}),t,null,[[6,12]])})))).apply(this,arguments)}var yr,wr={getQuote:function(t){var e=t.pool,n=t.reserves,r=t.poolTokenIn,a=BigInt(r),s=xr(a,n),o=s.asset1OutputAmount,i=s.asset2OutputAmount;return{round:n.round,asset1Out:{assetId:e.asset1ID,amount:o},asset2Out:{assetId:e.asset2ID,amount:i},poolTokenIn:{assetId:e.poolTokenID,amount:a}}},getSingleAssetRemoveLiquidityQuote:function(t){var e,n=t.pool,r=t.reserves,a=t.poolTokenIn,s=t.assetOutID,o=t.decimals,i=BigInt(a),u=xr(i,r),c=u.asset1OutputAmount,p=u.asset2OutputAmount,l=n.totalFeeShare;if(s===n.asset1ID){var d=Ir.calculateFixedInputSwap({inputSupply:r.asset2-p,outputSupply:r.asset1-c,swapInputAmount:p,totalFeeShare:l,decimals:o}),f=d.swapOutputAmount,m=d.totalFeeAmount,g=d.priceImpact;e={round:r.round,assetOut:{assetId:s,amount:c+f},poolTokenIn:{assetId:n.poolTokenID,amount:i},internalSwapQuote:{amountIn:{assetId:n.asset2ID,amount:p},amountOut:{assetId:n.asset1ID,amount:f},swapFees:{assetId:n.asset2ID,amount:m},priceImpact:g}}}else{if(s!==n.asset2ID)throw new Error("assetOutID must be one of the pool assets");var A=Ir.calculateFixedInputSwap({inputSupply:r.asset1-c,outputSupply:r.asset2-p,swapInputAmount:c,totalFeeShare:l,decimals:o}),I=A.swapOutputAmount,x=A.totalFeeAmount,h=A.priceImpact;e={round:r.round,assetOut:{assetId:s,amount:p+I},poolTokenIn:{assetId:n.poolTokenID,amount:i},internalSwapQuote:{amountIn:{assetId:n.asset2ID,amount:p},amountOut:{assetId:n.asset1ID,amount:I},swapFees:{assetId:n.asset2ID,amount:x},priceImpact:h}}}return e},generateTxns:function(t){return hr.apply(this,arguments)},generateSingleAssetOutTxns:function(t){return vr.apply(this,arguments)},signTxns:function(t){var e=t.txGroup;return(0,t.initiatorSigner)([e])},execute:function(t){return Tr.apply(this,arguments)}},_r=(p(yr={},C.V1_1,sr),p(yr,C.V2,wr),yr),br=3n,Er=1000n,Dr=function(t){return t[t.FEE_TXN_INDEX=0]="FEE_TXN_INDEX",t[t.VALIDATOR_APP_CALL_TXN_INDEX=1]="VALIDATOR_APP_CALL_TXN_INDEX",t[t.ASSET_IN_TXN_INDEX=2]="ASSET_IN_TXN_INDEX",t[t.ASSET_OUT_TXN_INDEX=3]="ASSET_OUT_TXN_INDEX",t}(Dr||{});function Sr(){return(Sr=o(a().mark((function e(n){var r,s,o,i,u,c,p,l;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.pool,s=n.txGroup,o=n.initiatorSigner,e.next=3,o([s]);case 3:return i=e.sent,u=h(i,2),c=u[0],p=u[1],l=s.map((function(e,n){return n===Dr.FEE_TXN_INDEX?c:n===Dr.ASSET_IN_TXN_INDEX?p:t.signLogicSigTransactionObject(e.txn,r.account.lsig).blob})),e.abrupt("return",l);case 9:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Or(){return(Or=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m,g,A,I,x,h,v,T,y,w;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=n.client,s=n.quoteAndPool,o=n.swapType,i=n.slippage,u=n.initiatorAddr,c=s.pool,p=s.quote,l=p.assetInID,d=p.assetOutID,f=c.account.address(),(m=[c.asset1ID,c.asset2ID]).includes(l)&&m.includes(d)&&l!==d){e.next=7;break}throw new W({pool:c,quote:p},"Input asset (#".concat(l,") and output asset (#").concat(d,") provided to generate transactions do not belong to the pool ").concat(f,"."));case 7:return e.next=9,r.getTransactionParams().do();case 9:return g=e.sent,A=[ht("swap"),o===Ot.FixedInput?ht("fi"):ht("fo")],I=t.makeApplicationNoOpTxnFromObject({from:f,appIndex:c.validatorAppID,appArgs:A,accounts:[u],note:Tt.getAppCallTxnNoteWithClientName(C.V1_1),foreignAssets:c.asset2ID==j?[c.asset1ID,c.poolTokenID]:[c.asset1ID,c.asset2ID,c.poolTokenID],suggestedParams:g}),x=o===Ot.FixedOutput?ct("positive",i,p.assetInAmount):p.assetInAmount,h=l===j?t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:f,amount:x,suggestedParams:g}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:u,to:f,assetIndex:l,amount:x,suggestedParams:g}),v=o===Ot.FixedInput?ct("negative",i,p.assetOutAmount):p.assetOutAmount,T=d===j?t.makePaymentTxnWithSuggestedParamsFromObject({from:f,to:u,amount:v,suggestedParams:g}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:f,to:u,assetIndex:d,amount:v,suggestedParams:g}),y=t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:f,amount:I.fee+T.fee,note:D,suggestedParams:g}),w=t.assignGroupID([y,I,h,T]),e.abrupt("return",[{txn:w[0],signers:[u]},{txn:w[1],signers:[f]},{txn:w[2],signers:[u]},{txn:w[3],signers:[f]}]);case 19:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Nr(t){var e=t.pool,n=t.reserves,a=t.assetIn,s=t.decimals;if(e.status!==Se.READY)throw new E(b.NoAvailablePoolError,"There is not an available pool for this asset pair");var o,i,u,c=BigInt(a.amount);if(a.id===e.asset1ID)o=e.asset2ID,i=n.asset1,u=n.asset2;else{if(a.id!==e.asset2ID)throw new E(b.AssetDoesNotBelongToPoolError,"Input asset (#".concat(a.id,") doesn't belong to the pool ").concat(e.account.address(),"."));o=e.asset1ID,i=n.asset2,u=n.asset1}var p=c*br/Er,l=u-i*u/(i+(c-p));if(l>u)throw new E(b.OutputAmountExceedsAvailableLiquidityError,"Output amount exceeds available liquidity.");var d={assetIn:{amount:c,decimals:s.assetIn},assetOut:{amount:l,decimals:s.assetOut}},f={round:n.round,assetInID:a.id,assetInAmount:c,assetOutID:o,assetOutAmount:l,swapFee:Number(p),rate:ae(d),priceImpact:se(r({inputSupply:i,outputSupply:u},d))};return{type:Zt.Direct,data:{pool:e,quote:f}}}function Pr(t){return kr.apply(this,arguments)}function kr(){return(kr=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d,f,m,g,A,I,x;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.signedTxns,o=e.assetIn,i=e.assetOut,u=e.initiatorAddr,t.next=3,_e({client:n,pool:r,accountAddr:u});case 3:return c=t.sent,t.next=6,mt(n,[s]);case 6:return p=t.sent,l=h(p,1),d=l[0],f=d.confirmedRound,m=d.txnID,t.next=13,_e({client:n,pool:r,accountAddr:u});case 13:return g=t.sent,i.id===r.asset1ID?(A=c.excessAsset1,I=g.excessAsset1):(A=c.excessAsset2,I=g.excessAsset2),(x=I-A)<0n&&(x=0n),t.abrupt("return",{round:f,assetInID:o.id,assetInAmount:BigInt(o.amount),assetOutID:i.id,assetOutAmount:BigInt(i.amount)+x,excessAmount:{assetID:i.id,excessAmountForSwap:x,totalExcessAmount:I},txnID:m});case 18:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Lr(t){var e=t.pool,n=t.reserves,r=t.assetOut,a=t.decimals;if(e.status!==Se.READY)throw new E(b.NoAvailablePoolError,"There is not an available pool for this asset pair");var s,o,i,u=BigInt(r.amount);if(r.id===e.asset1ID)s=e.asset2ID,o=n.asset2,i=n.asset1;else{if(r.id!==e.asset2ID)throw new E(b.AssetDoesNotBelongToPoolError,"Output asset (#".concat(r.id,") doesn't belong to the pool ").concat(e.account.address(),"."));s=e.asset1ID,o=n.asset1,i=n.asset2}if(u>i)throw new E(b.OutputAmountExceedsAvailableLiquidityError,"Output amount exceeds available liquidity.");var c=o*i/(i-u)-o,p=c*Er/(Er-br),l=p-c,d=pt(a.assetOut,Number(u))/pt(a.assetIn,Number(p)),f=pt(a.assetOut,Number(i))/pt(a.assetIn,Number(o)),m=lt({decimalPlaces:5},Math.abs(d/f-1)),g={round:n.round,assetInID:s,assetInAmount:p,assetOutID:r.id,assetOutAmount:u,swapFee:Number(l),rate:d,priceImpact:m};return{type:Zt.Direct,data:{pool:e,quote:g}}}function Rr(t){return Fr.apply(this,arguments)}function Fr(){return(Fr=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d,f,m,g,A,I,x;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.signedTxns,o=e.assetIn,i=e.assetOut,u=e.initiatorAddr,t.next=3,_e({client:n,pool:r,accountAddr:u});case 3:return c=t.sent,t.next=6,mt(n,[s]);case 6:return p=t.sent,l=h(p,1),d=l[0],f=d.confirmedRound,m=d.txnID,t.next=13,_e({client:n,pool:r,accountAddr:u});case 13:return g=t.sent,o.id===r.asset1ID?(A=c.excessAsset1,I=g.excessAsset1):(A=c.excessAsset2,I=g.excessAsset2),(x=I-A)<0n&&(x=0n),t.abrupt("return",{round:f,assetInID:o.id,assetInAmount:BigInt(o.amount)-x,assetOutID:i.id,assetOutAmount:BigInt(i.amount),excessAmount:{assetID:o.id,excessAmountForSwap:x,totalExcessAmount:I},txnID:m});case 18:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Br(){return(Br=o(a().mark((function t(e){var n,s,o,i,u,c,p,l,d,f;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(n=e.client,s=e.pool,o=e.swapType,i=e.txGroup,u=e.signedTxns,c=e.initiatorAddr,s.status===Se.READY){t.next=3;break}throw new W({pool:s,swapType:o,txGroup:i},"There is not an available pool for this asset pair");case 3:if(t.prev=3,p={id:i[Dr.ASSET_IN_TXN_INDEX].txn.assetIndex||j,amount:i[Dr.ASSET_IN_TXN_INDEX].txn.amount},l={id:i[Dr.ASSET_OUT_TXN_INDEX].txn.assetIndex||j,amount:i[Dr.ASSET_OUT_TXN_INDEX].txn.amount},o!==Ot.FixedInput){t.next=12;break}return t.next=9,Pr({client:n,pool:s,signedTxns:u,assetIn:p,assetOut:l,initiatorAddr:c});case 9:d=t.sent,t.next=15;break;case 12:return t.next=14,Rr({client:n,pool:s,signedTxns:u,assetIn:p,assetOut:l,initiatorAddr:c});case 14:d=t.sent;case 15:return t.abrupt("return",r(r({},d),{},{groupID:It(i),fees:At(i)}));case 18:throw t.prev=18,t.t0=t.catch(3),"SlippageTolerance"===(f=new W(t.t0,"We encountered something unexpected while swapping. Try again later.")).type&&f.setMessage("The swap failed due to too much slippage in the price. Please adjust the slippage tolerance and try again."),f;case 23:case"end":return t.stop()}}),t,null,[[3,18]])})))).apply(this,arguments)}var Mr,Cr={getQuote:function(t,e,n,r,a){return t===Ot.FixedInput?Nr({pool:e,reserves:n,assetIn:r,decimals:a}):Lr({pool:e,reserves:n,assetOut:r,decimals:a})},getFixedInputSwapQuote:Nr,getFixedOutputSwapQuote:Lr,generateTxns:function(t){return Or.apply(this,arguments)},signTxns:function(t){return Sr.apply(this,arguments)},execute:function(t){return Br.apply(this,arguments)},executeFixedOutputSwap:Rr};function jr(t){return Promise.allSettled(t).then((function(t){if(t.every((function(t){return"rejected"===t.status}))){var e=h(t.map((function(t){return t.reason})),2),n=e[0],r=e[1];if(le(n)&&!le(r))throw n;throw r}return t.filter((function(t){return"fulfilled"===t.status&&t.value})).map((function(t){return t.value}))}))}function Vr(){return(Vr=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return r=e.amount,s=e.assetIn,o=e.assetOut,i=e.isSwapRouterEnabled,u=e.pools,c=[],(p=u.find((function(t){return t.info.contractVersion===C.V1_1})))?c.push(new Promise((function(t,e){try{t(Cr.getFixedInputSwapQuote({pool:p.info,assetIn:{amount:r,id:Number(s.id)},decimals:{assetIn:s.decimals,assetOut:o.decimals},reserves:p.reserves}))}catch(t){e(t)}}))):c.push(Promise.reject(new E(b.NoAvailablePoolError,"Trying to swap from non-existent pool"))),l=u.find((function(t){return t.info.contractVersion===C.V2})),c.push(Ir.getFixedInputSwapQuote({amount:r,assetIn:{id:H(s),decimals:s.decimals},assetOut:{id:H(o),decimals:o.decimals},pool:null!==(n=null==l?void 0:l.info)&&void 0!==n?n:null,isSwapRouterEnabled:i,network:e.network})),t.next=8,jr(c);case 8:return d=t.sent,t.abrupt("return",pe(d));case 10:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function Xr(){return(Xr=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return r=e.amount,s=e.assetIn,o=e.assetOut,i=e.pools,u=e.isSwapRouterEnabled,c=[],(p=i.find((function(t){return t.info.contractVersion===C.V1_1})))?c.push(new Promise((function(t,e){try{t(Cr.getFixedOutputSwapQuote({pool:p.info,assetOut:{amount:r,id:Number(o.id)},decimals:{assetIn:s.decimals,assetOut:o.decimals},reserves:p.reserves}))}catch(t){e(t)}}))):c.push(Promise.reject(new E(b.NoAvailablePoolError,"Trying to swap from non-existent pool"))),l=i.find((function(t){return t.info.contractVersion===C.V2})),c.push(Ir.getFixedOutputSwapQuote({amount:r,assetIn:{id:H(s),decimals:s.decimals},assetOut:{id:H(o),decimals:o.decimals},pool:null!==(n=null==l?void 0:l.info)&&void 0!==n?n:null,isSwapRouterEnabled:u,network:e.network})),t.next=8,jr(c);case 8:return d=t.sent,t.abrupt("return",pe(d));case 10:case"end":return t.stop()}}),t)})))).apply(this,arguments)}var Qr=(p(Mr={},C.V1_1,Cr),p(Mr,C.V2,Ir),p(Mr,"getQuote",(function(t){var e=t.type;if(e===Ot.FixedInput)return function(t){return Vr.apply(this,arguments)}(t);if(e===Ot.FixedOutput)return function(t){return Xr.apply(this,arguments)}(t);throw new E(b.InvalidSwapTypeError,"Invalid swap type")})),p(Mr,"generateTxns",(function(t){return t.quote.type===Zt.Direct&&ue(t.quote)===C.V1_1?Cr.generateTxns(r(r({},t),{},{quoteAndPool:t.quote.data})):Ir.generateTxns(t)})),p(Mr,"signTxns",(function(t){if(t.quote.type===Zt.Direct&&ue(t.quote)===C.V1_1){var e=t.quote.data.pool;return Cr.signTxns(r(r({},t),{},{pool:e}))}return Ir.signTxns(t)})),p(Mr,"execute",(function(t){return t.contractVersion===C.V1_1?Cr.execute(t):Ir.execute(t)})),Mr);function Ur(){return(Ur=o(a().mark((function t(e){var n,r,s,o,i,u,c,p,l,d;return a().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=e.client,r=e.pool,s=e.txGroup,o=e.initiatorSigner,t.prev=1,t.next=4,qr({txGroup:s,pool:r,initiatorSigner:o});case 4:return i=t.sent,t.next=7,mt(n,[i]);case 7:return u=t.sent,c=h(u,1),p=c[0],l=p.txnID,d=p.confirmedRound,t.abrupt("return",{fees:At(s),confirmedRound:d,txnID:l,groupID:It(s)});case 15:throw t.prev=15,t.t0=t.catch(1),new W(t.t0,"We encountered something unexpected while redeeming. Try again later.");case 18:case"end":return t.stop()}}),t,null,[[1,15]])})))).apply(this,arguments)}function qr(t){return Gr.apply(this,arguments)}function Gr(){return(Gr=o(a().mark((function e(n){var r,s,o,i,u,c,p,l;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.txGroup,s=n.pool,o=n.initiatorSigner,e.next=3,o([r]);case 3:return i=e.sent,u=h(i,1),c=u[0],p=s.account.lsig,l=r.map((function(e,n){return 0===n?c:t.signLogicSigTransactionObject(e.txn,p).blob})),e.abrupt("return",l);case 9:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Wr(){return Wr=o(a().mark((function e(n){var r,s,i,u,c,p;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.data,i=n.initiatorSigner,e.prev=1,u=s.map((function(t){var e=t.txGroup,n=t.pool;return{txns:e,txnFees:At(e),groupID:It(e),lsig:n.account.lsig}})),e.next=5,i(u.map((function(t){return t.txns})));case 5:return c=e.sent,p=Promise.all(u.map((function(e,n){return new Promise(function(){var s=o(a().mark((function s(o,i){var u,p,l,d,f,m;return a().wrap((function(a){for(;;)switch(a.prev=a.next){case 0:return a.prev=0,u=e.txns.map((function(r,a){return 0===a?c[n]:t.signLogicSigTransactionObject(r.txn,e.lsig).blob})),a.next=4,mt(r,[u]);case 4:p=a.sent,l=h(p,1),d=l[0],f=d.txnID,m=d.confirmedRound,o({fees:e.txnFees,groupID:e.groupID,txnID:f,confirmedRound:m}),a.next=15;break;case 12:a.prev=12,a.t0=a.catch(0),i(a.t0);case 15:case"end":return a.stop()}}),s,null,[[0,12]])})));return function(t,e){return s.apply(this,arguments)}}())}))),e.abrupt("return",p);case 10:throw e.prev=10,e.t0=e.catch(1),new W(e.t0,"We encountered something unexpected while redeeming. Try again later.");case 13:case"end":return e.stop()}}),e,null,[[1,10]])}))),Wr.apply(this,arguments)}function zr(){return(zr=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.pool,o=n.assetID,i=n.assetOut,u=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:return c=e.sent,p=s.account.address(),l=t.makeApplicationNoOpTxnFromObject({from:p,appIndex:s.validatorAppID,appArgs:[ht("redeem")],note:Tt.getAppCallTxnNoteWithClientName(s.contractVersion),accounts:[u],foreignAssets:0==s.asset2ID?[s.asset1ID,s.poolTokenID]:[s.asset1ID,s.asset2ID,s.poolTokenID],suggestedParams:c}),d=0===o?t.makePaymentTxnWithSuggestedParamsFromObject({from:p,to:u,amount:BigInt(i),suggestedParams:c}):t.makeAssetTransferTxnWithSuggestedParamsFromObject({from:p,to:u,assetIndex:o,amount:BigInt(i),suggestedParams:c}),f=t.makePaymentTxnWithSuggestedParamsFromObject({from:u,to:p,amount:l.fee+d.fee,note:D,suggestedParams:c}),m=t.assignGroupID([f,l,d]),e.abrupt("return",[{txn:m[0],signers:[u]},{txn:m[1],signers:[p]},{txn:m[2],signers:[p]}]);case 10:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function Jr(e){var n=e.suggestedParams,r=e.stakingAppID,a=e.initiatorAddr,s=e.liquidityAssetID,o=e.program,i=e.amount,u=t.encodeUint64(i),c=t.encodeUint64(o.id);return t.makeApplicationNoOpTxnFromObject({appIndex:r,from:a,suggestedParams:n,foreignAssets:[s],accounts:[o.accountAddress],appArgs:[ht("commit"),u],note:$([ht("tinymanStaking/v1:b"),c,t.encodeUint64(s),u])})}function Yr(){return(Yr=o(a().mark((function e(n){var r,s,o,i,u,c,p,l,d,f,m;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.client,s=n.stakingAppID,o=n.program,i=n.requiredAssetID,u=n.liquidityAssetID,c=n.amount,p=n.initiatorAddr,e.next=3,r.getTransactionParams().do();case 3:if(l=e.sent,d=Jr({suggestedParams:l,stakingAppID:s,program:o,liquidityAssetID:u,initiatorAddr:p,amount:c}),f=[d],"number"!=typeof i){e.next=10;break}return m=t.makeApplicationNoOpTxnFromObject({appIndex:s,from:p,suggestedParams:l,foreignAssets:[i],accounts:[o.accountAddress],appArgs:[ht("log_balance")]}),f=t.assignGroupID([d,m]),e.abrupt("return",[{txn:f[0],signers:[p]},{txn:f[1],signers:[p]}]);case 10:return e.abrupt("return",[{txn:f[0],signers:[p]}]);case 11:case"end":return e.stop()}}),e)})))).apply(this,arguments)}exports.ALGO_ASSET=V,exports.ALGO_ASSET_ID=j,exports.ASSET_OPT_IN_PROCESS_TXN_COUNT=1,exports.AddLiquidity=Kn,exports.BASE_MINIMUM_BALANCE=S,exports.Bootstrap=yn,exports.CONTRACT_VERSION=C,exports.MINIMUM_ADD_LIQUIDITY_AMOUNT=F,exports.MINIMUM_BALANCE_REQUIRED_PER_APP=N,exports.MINIMUM_BALANCE_REQUIRED_PER_ASSET=O,exports.MINIMUM_BALANCE_REQUIRED_PER_BYTE_SCHEMA=L,exports.MINIMUM_BALANCE_REQUIRED_PER_INT_SCHEMA_VALUE=R,exports.OPT_IN_VALIDATOR_APP_PROCESS_TXN_COUNT=1,exports.OPT_OUT_VALIDATOR_APP_PROCESS_TXN_COUNT=1,exports.POOL_TOKEN_UNIT_NAME=X,exports.PoolStatus=Se,exports.REDEEM_PROCESS_TXN_COUNT=3,exports.RemoveLiquidity=_r,exports.Swap=Qr,exports.SwapQuoteError=E,exports.SwapQuoteErrorType=b,exports.SwapQuoteType=Zt,exports.SwapType=Ot,exports.V1_1AddLiquidityTxnIndices=wn,exports.V1_1_ADD_LIQUIDITY_PROCESS_TXN_COUNT=5,exports.V1_1_REMOVE_LIQUIDITY_TXN_COUNT=Zn,exports.V2AddLiquidityTxnIndices=En,exports.V2AddLiquidityType=bn,exports.V2_REMOVE_LIQUIDITY_APP_CALL_INNER_TXN_COUNT=$n,exports.applySlippageToAmount=ct,exports.calculateAccountMinimumRequiredBalance=ye,exports.calculatePriceImpact=se,exports.calculateSwapRate=ae,exports.combineAndRegroupSignerTxns=function(){for(var e=arguments.length,n=new Array(e),a=0;a=t.minimum_required_balance},exports.isAccountOptedIntoApp=function(t){var e=t.appID;return t.accountAppsLocalState.some((function(t){return t.id===e}))},exports.isSwapAssetInAmountLow=ne,exports.isSwapQuoteErrorCausedByAmount=le,exports.poolUtils=We,exports.prepareCommitTransactions=function(t){return Yr.apply(this,arguments)},exports.redeemAllExcessAsset=function(t){return Wr.apply(this,arguments)},exports.redeemExcessAsset=function(t){return Ur.apply(this,arguments)},exports.sendAndWaitRawTransaction=mt,exports.sumUpTxnFees=At,exports.tinymanContract_v1_1=ge,exports.tinymanContract_v2=xe,exports.tinymanJSSDKConfig=Tt; diff --git a/dist/swap/common/utils.d.ts b/dist/swap/common/utils.d.ts index 2d87a35e..6574cb21 100644 --- a/dist/swap/common/utils.d.ts +++ b/dist/swap/common/utils.d.ts @@ -1,4 +1,8 @@ -import { AssetWithAmountAndDecimals } from "../../util/asset/assetModels"; +import { CONTRACT_VERSION } from "../../contract/constants"; +import { ContractVersionValue } from "../../contract/types"; +import { AssetWithAmountAndDecimals, AssetWithIdAndAmount } from "../../util/asset/assetModels"; +import { SwapType } from "../constants"; +import { SwapQuote } from "../types"; declare function calculateSwapRate({ assetIn, assetOut }: { assetIn: AssetWithAmountAndDecimals; assetOut: AssetWithAmountAndDecimals; @@ -9,4 +13,31 @@ declare function calculatePriceImpact({ inputSupply, outputSupply, assetIn, asse assetIn: AssetWithAmountAndDecimals; assetOut: AssetWithAmountAndDecimals; }): number; -export { calculateSwapRate, calculatePriceImpact }; +declare function getSwapQuotePriceImpact(quote: SwapQuote): number; +declare function getAssetInFromSwapQuote(quote: SwapQuote): AssetWithIdAndAmount; +declare function getAssetOutFromSwapQuote(quote: SwapQuote): AssetWithIdAndAmount; +declare function getAssetInAndAssetOutFromSwapQuote(quote: SwapQuote): { + assetIn: AssetWithIdAndAmount; + assetOut: AssetWithIdAndAmount; +}; +declare function getSwapQuoteContractVersion(quote: SwapQuote): ContractVersionValue; +/** + * @returns the total fee that will be paid by the user + * for the swap transaction with given parameters + */ +declare function getSwapTotalFee(params: { + version: typeof CONTRACT_VERSION.V1_1; +} | { + version: typeof CONTRACT_VERSION.V2; + type: SwapType; +}): number; +/** + * @returns The asset amount ratio for the given quote + */ +declare function getSwapQuoteRate(quote: SwapQuote): number; +/** + * Compares the given quotes and returns the best one (with the highest rate). + */ +declare function getBestQuote(quotes: SwapQuote[]): SwapQuote; +declare function isSwapQuoteErrorCausedByAmount(error: Error): boolean; +export { calculateSwapRate, calculatePriceImpact, getSwapQuotePriceImpact, getAssetInFromSwapQuote, getAssetOutFromSwapQuote, getAssetInAndAssetOutFromSwapQuote, getSwapQuoteContractVersion, getSwapTotalFee, getSwapQuoteRate, getBestQuote, isSwapQuoteErrorCausedByAmount }; diff --git a/dist/swap/constants.d.ts b/dist/swap/constants.d.ts index c5a3af4d..fe4d5ef0 100644 --- a/dist/swap/constants.d.ts +++ b/dist/swap/constants.d.ts @@ -2,3 +2,4 @@ export declare enum SwapType { FixedInput = "fixed-input", FixedOutput = "fixed-output" } +export declare const DEFAULT_SWAP_FEE_RATE = 0.003; diff --git a/dist/swap/index.d.ts b/dist/swap/index.d.ts index 08373cd0..677b5e52 100644 --- a/dist/swap/index.d.ts +++ b/dist/swap/index.d.ts @@ -23,15 +23,7 @@ export declare const Swap: { assetOut: number; }; }) => import("./types").SwapQuote; - generateTxns: ({ client, pool, swapType, assetIn, assetOut, slippage, initiatorAddr }: { - client: import("algosdk").Algodv2; - pool: import("..").V1PoolInfo; - swapType: import("./constants").SwapType; - assetIn: import("../util/asset/assetModels").AssetWithIdAndAmount; - assetOut: import("../util/asset/assetModels").AssetWithIdAndAmount; - slippage: number; - initiatorAddr: string; - }) => Promise; + generateTxns: ({ client, quoteAndPool, swapType, slippage, initiatorAddr }: import("./types").GenerateV1_1SwapTxnsParams) => Promise; signTxns: ({ pool, txGroup, initiatorSigner }: { pool: import("..").V1PoolInfo; txGroup: import("..").SignerTransaction[]; @@ -55,46 +47,53 @@ export declare const Swap: { }) => Promise>; }; v2: { - getQuote: (type: import("./constants").SwapType, pool: import("..").V2PoolInfo, asset: import("../util/asset/assetModels").AssetWithIdAndAmount, decimals: { - assetIn: number; - assetOut: number; - }) => import("./types").SwapQuote; - getFixedInputSwapQuote: ({ pool, assetIn, decimals }: { - pool: import("..").V2PoolInfo; - assetIn: import("../util/asset/assetModels").AssetWithIdAndAmount; - decimals: { - assetIn: number; - assetOut: number; - }; - }) => import("./types").SwapQuote; - getFixedOutputSwapQuote: ({ pool, assetOut, decimals }: { + getQuote: ({ type, amount, assetIn, assetOut, network, isSwapRouterEnabled, pool }: { + type: import("./constants").SwapType; + amount: number | bigint; + assetIn: import("../util/asset/assetModels").AssetWithIdAndDecimals; + assetOut: import("../util/asset/assetModels").AssetWithIdAndDecimals; + pool: import("..").V2PoolInfo | null; + network: import("..").SupportedNetwork; + isSwapRouterEnabled?: boolean | undefined; + }) => Promise; + getFixedInputSwapQuote: ({ amount, assetIn, assetOut, isSwapRouterEnabled, network, pool }: { + amount: number | bigint; + assetIn: import("../util/asset/assetModels").AssetWithIdAndDecimals; + assetOut: import("../util/asset/assetModels").AssetWithIdAndDecimals; + network: import("..").SupportedNetwork; + pool: import("..").V2PoolInfo | null; + isSwapRouterEnabled?: boolean | undefined; + }) => Promise; + getFixedInputDirectSwapQuote: ({ amount, assetIn, assetOut, pool }: { pool: import("..").V2PoolInfo; - assetOut: import("../util/asset/assetModels").AssetWithIdAndAmount; - decimals: { - assetIn: number; - assetOut: number; - }; + amount: number | bigint; + assetIn: import("../util/asset/assetModels").AssetWithIdAndDecimals; + assetOut: import("../util/asset/assetModels").AssetWithIdAndDecimals; + }) => import("./types").DirectSwapQuote; + getFixedOutputDirectSwapQuote: ({ amount, assetIn, assetOut, pool }: { + pool: import("..").V2PoolInfo | null; + amount: number | bigint; + assetIn: import("../util/asset/assetModels").AssetWithIdAndDecimals; + assetOut: import("../util/asset/assetModels").AssetWithIdAndDecimals; }) => import("./types").SwapQuote; - generateTxns: ({ client, pool, swapType, assetIn, assetOut, initiatorAddr, slippage }: { - client: import("algosdk").Algodv2; - pool: import("..").V2PoolInfo; - swapType: import("./constants").SwapType; - assetIn: import("../util/asset/assetModels").AssetWithIdAndAmount; - assetOut: import("../util/asset/assetModels").AssetWithIdAndAmount; - initiatorAddr: string; - slippage: number; - }) => Promise; + getFixedOutputSwapQuote: ({ amount, assetIn, assetOut, isSwapRouterEnabled, network, pool }: { + amount: number | bigint; + assetIn: import("../util/asset/assetModels").AssetWithIdAndDecimals; + assetOut: import("../util/asset/assetModels").AssetWithIdAndDecimals; + pool: import("..").V2PoolInfo | null; + network: import("..").SupportedNetwork; + isSwapRouterEnabled?: boolean | undefined; + }) => Promise; + generateTxns: (params: import("./types").GenerateSwapTxnsParams) => Promise; signTxns: ({ txGroup, initiatorSigner }: { txGroup: import("..").SignerTransaction[]; initiatorSigner: import("..").InitiatorSigner; }) => Promise; - execute: ({ client, pool, txGroup, signedTxns, network, assetIn }: { + execute: ({ client, quote, txGroup, signedTxns }: { client: import("algosdk").Algodv2; - pool: import("..").V2PoolInfo; - network: import("..").SupportedNetwork; + quote: import("./types").SwapQuote; txGroup: import("..").SignerTransaction[]; signedTxns: Uint8Array[]; - assetIn: import("../util/asset/assetModels").AssetWithIdAndAmount; }) => Promise; calculateFixedInputSwap: ({ inputSupply, outputSupply, swapInputAmount, totalFeeShare, decimals }: { inputSupply: bigint; diff --git a/dist/swap/types.d.ts b/dist/swap/types.d.ts index ffa07383..94143b80 100644 --- a/dist/swap/types.d.ts +++ b/dist/swap/types.d.ts @@ -1,7 +1,13 @@ -import { AssetWithIdAndAmount } from "../util/asset/assetModels"; +import { Algodv2 } from "algosdk"; +import { AssetWithIdAndAmount, TinymanAnalyticsApiAsset } from "../util/asset/assetModels"; +import { SignerTransaction, SupportedNetwork } from "../util/commonTypes"; import { PoolReserves, V1PoolInfo, V2PoolInfo } from "../util/pool/poolTypes"; -/** An object containing information about a swap quote. */ -export interface SwapQuote { +import { SwapType } from "./constants"; +export declare enum SwapQuoteType { + Direct = "direct", + Router = "router" +} +export interface DirectSwapQuote { /** The ID of the input asset in this quote. */ assetInID: number; /** The quantity of the input asset in this quote. */ @@ -19,6 +25,89 @@ export interface SwapQuote { /** The round that this quote is based on. */ round?: number; } +export interface DirectSwapQuoteAndPool { + quote: DirectSwapQuote; + pool: V1PoolInfo | V2PoolInfo; +} +export interface SwapRouteAsset { + id: string; + name: string; + unit_name: string; + decimals: number; +} +export interface SwapRoutePool { + address: string; + asset_1: SwapRouteAsset; + asset_2: SwapRouteAsset; + version: "2.0"; +} +export type SwapRoute = { + quote: SwapRouterQuote; + pool: SwapRoutePool; +}[]; +export interface SwapRouterQuote { + swap_type: SwapType; + amount_in: { + asset: SwapRouteAsset; + amount: string; + }; + amount_out: { + asset: SwapRouteAsset; + amount: string; + }; + swap_fees: { + amount: string; + asset: SwapRouteAsset; + }; + price: number; + price_impact: number; +} +export interface FetchSwapRouteQuotesPayload { + asset_in_id: string; + asset_out_id: string; + amount: string; + swap_type: SwapType; +} +export type SwapRouterResponse = FetchSwapRouteQuotesPayload & { + route: SwapRoute; + price_impact: string; + status: { + round_number: string; + round_datetime: string; + }; +}; +export type GetSwapQuoteParams = { + assetIn: Pick; + assetOut: Pick; + pools: { + info: V1PoolInfo | V2PoolInfo; + reserves: PoolReserves; + }[]; + amount: number | bigint; + type: SwapType; + network: SupportedNetwork; + /** If `true`, the function will also check the quotes that use swap route */ + isSwapRouterEnabled?: boolean; +}; +export type SwapQuote = { + data: DirectSwapQuoteAndPool; + type: SwapQuoteType.Direct; +} | { + data: SwapRouterResponse; + type: SwapQuoteType.Router; +}; +export type GetSwapQuoteBySwapTypeParams = Omit; +export interface GenerateSwapTxnsParams { + client: Algodv2; + network: SupportedNetwork; + quote: SwapQuote; + swapType: SwapType; + slippage: number; + initiatorAddr: string; +} +export type GenerateV1_1SwapTxnsParams = Omit & { + quoteAndPool: DirectSwapQuoteAndPool; +}; /** An object containing information about a successfully executed swap. */ export interface V1SwapExecution { /** The round that the swap occurred in. */ @@ -54,14 +143,12 @@ export interface V2SwapExecution { /** Can be `undefined` if the execution was successful, but there was an issue while * extracting the output asset data from the transaction response */ assetOut: AssetWithIdAndAmount | undefined; - pool: V2PoolInfo; + quote: SwapQuote; txnID: string; round: number; } -export interface SwapQuoteWithPool { - quote: SwapQuote; - pool: { - info: V1PoolInfo | V2PoolInfo; - reserves: PoolReserves; - }; +export interface ExecuteSwapCommonParams { + client: Algodv2; + txGroup: SignerTransaction[]; + signedTxns: Uint8Array[]; } diff --git a/dist/swap/utils.d.ts b/dist/swap/utils.d.ts index 68f37371..cf404059 100644 --- a/dist/swap/utils.d.ts +++ b/dist/swap/utils.d.ts @@ -1,88 +1,34 @@ -import { Algodv2 } from "algosdk"; import { CONTRACT_VERSION } from "../contract/constants"; -import { AssetWithIdAndAmount, TinymanAnalyticsApiAsset } from "../util/asset/assetModels"; -import { InitiatorSigner, SignerTransaction, SupportedNetwork } from "../util/commonTypes"; -import { PoolReserves, V1PoolInfo, V2PoolInfo } from "../util/pool/poolTypes"; -import { SwapQuoteWithPool } from "./types"; +import { InitiatorSigner, SignerTransaction } from "../util/commonTypes"; +import { V1PoolInfo } from "../util/pool/poolTypes"; +import { GetSwapQuoteBySwapTypeParams, GenerateSwapTxnsParams, GetSwapQuoteParams, SwapQuote, ExecuteSwapCommonParams } from "./types"; import { SwapType } from "./constants"; /** - * Gets quotes for swap from each pool passed as an argument, - * and returns the best quote (with the highest rate). + * Gets the best quote for swap from the pools and swap router and returns the best option. */ -export declare function getQuote(params: { - type: SwapType; - pools: { - info: V1PoolInfo | V2PoolInfo; - reserves: PoolReserves; - }[]; - assetIn: Pick; - assetOut: Pick; - amount: number | bigint; -}): Promise; +export declare function getQuote(params: GetSwapQuoteParams): Promise; /** - * Gets quotes for fixed input swap from each pool passed as an argument, + * Gets quotes for fixed input swap the pools and swap router, * and returns the best quote (with the highest rate). */ -export declare function getFixedInputSwapQuote({ pools, assetIn, assetOut, amount }: { - pools: { - info: V1PoolInfo | V2PoolInfo; - reserves: PoolReserves; - }[]; - assetIn: Pick; - assetOut: Pick; - amount: number | bigint; -}): Promise; +export declare function getFixedInputSwapQuote(params: GetSwapQuoteBySwapTypeParams): Promise; /** - * Gets quotes for fixed output swap from each pool passed as an argument, + * Gets quotes for fixed output swap from the pools and swap router, * and returns the best quote (with the highest rate). */ -export declare function getFixedOutputSwapQuote({ pools, assetIn, assetOut, amount }: { - pools: { - info: V1PoolInfo | V2PoolInfo; - reserves: PoolReserves; - }[]; - assetIn: Pick; - assetOut: Pick; - amount: number | bigint; -}): Promise; -export declare function generateTxns(params: { - client: Algodv2; - pool: V1PoolInfo | V2PoolInfo; - poolAddress: string; - swapType: SwapType; - assetIn: AssetWithIdAndAmount; - assetOut: AssetWithIdAndAmount; - slippage: number; - initiatorAddr: string; -}): Promise; +export declare function getFixedOutputSwapQuote(params: GetSwapQuoteBySwapTypeParams): Promise; +export declare function generateTxns(params: GenerateSwapTxnsParams): Promise; export declare function signTxns(params: { - pool: V1PoolInfo; + quote: SwapQuote; txGroup: SignerTransaction[]; initiatorSigner: InitiatorSigner; }): Promise; -interface ExecuteCommonParams { - swapType: SwapType; - client: Algodv2; - pool: V2PoolInfo; - network: SupportedNetwork; - txGroup: SignerTransaction[]; - signedTxns: Uint8Array[]; - assetIn: AssetWithIdAndAmount; -} export declare function execute(params: ({ contractVersion: typeof CONTRACT_VERSION.V1_1; initiatorAddr: string; + pool: V1PoolInfo; + swapType: SwapType; } | { contractVersion: typeof CONTRACT_VERSION.V2; -}) & ExecuteCommonParams): Promise | Promise; -/** - * @returns the total fee that will be paid by the user - * for the swap transaction with given parameters - */ -export declare function getSwapTotalFee(params: { - version: typeof CONTRACT_VERSION.V1_1; -} | { - version: typeof CONTRACT_VERSION.V2; - type: SwapType; -}): number; -export {}; + quote: SwapQuote; +}) & ExecuteSwapCommonParams): Promise | Promise; diff --git a/dist/swap/v1_1/index.d.ts b/dist/swap/v1_1/index.d.ts index 8da014a9..4117d8bc 100644 --- a/dist/swap/v1_1/index.d.ts +++ b/dist/swap/v1_1/index.d.ts @@ -1,7 +1,7 @@ import { Algodv2 } from "algosdk"; import { InitiatorSigner, SignerTransaction } from "../../util/commonTypes"; import { PoolReserves, V1PoolInfo } from "../../util/pool/poolTypes"; -import { SwapQuote, V1SwapExecution } from "../types"; +import { GenerateV1_1SwapTxnsParams, SwapQuote, V1SwapExecution } from "../types"; import { SwapType } from "../constants"; import { AssetWithIdAndAmount } from "../../util/asset/assetModels"; declare function signTxns({ pool, txGroup, initiatorSigner }: { @@ -9,15 +9,7 @@ declare function signTxns({ pool, txGroup, initiatorSigner }: { txGroup: SignerTransaction[]; initiatorSigner: InitiatorSigner; }): Promise; -declare function generateTxns({ client, pool, swapType, assetIn, assetOut, slippage, initiatorAddr }: { - client: Algodv2; - pool: V1PoolInfo; - swapType: SwapType; - assetIn: AssetWithIdAndAmount; - assetOut: AssetWithIdAndAmount; - slippage: number; - initiatorAddr: string; -}): Promise; +declare function generateTxns({ client, quoteAndPool, swapType, slippage, initiatorAddr }: GenerateV1_1SwapTxnsParams): Promise; /** * * @param type - Type of the swap diff --git a/dist/swap/v2/constants.d.ts b/dist/swap/v2/constants.d.ts index 1adbd66a..a07c9c4d 100644 --- a/dist/swap/v2/constants.d.ts +++ b/dist/swap/v2/constants.d.ts @@ -18,3 +18,6 @@ export declare const V2_SWAP_APP_CALL_SWAP_TYPE_ARGS_ENCODED: { readonly "fixed-input": Uint8Array; readonly "fixed-output": Uint8Array; }; +export declare const V2_SWAP_ROUTER_APP_ARGS_ENCODED: { + readonly ASSET_OPT_IN: Uint8Array; +}; diff --git a/dist/swap/v2/index.d.ts b/dist/swap/v2/index.d.ts index e21b3207..5032dd0c 100644 --- a/dist/swap/v2/index.d.ts +++ b/dist/swap/v2/index.d.ts @@ -1,18 +1,10 @@ import { Algodv2 } from "algosdk"; import { InitiatorSigner, SignerTransaction, SupportedNetwork } from "../../util/commonTypes"; import { V2PoolInfo } from "../../util/pool/poolTypes"; -import { SwapQuote, V2SwapExecution } from "../types"; +import { DirectSwapQuote, GenerateSwapTxnsParams, SwapQuote, V2SwapExecution } from "../types"; import { SwapType } from "../constants"; -import { AssetWithIdAndAmount } from "../../util/asset/assetModels"; -declare function generateTxns({ client, pool, swapType, assetIn, assetOut, initiatorAddr, slippage }: { - client: Algodv2; - pool: V2PoolInfo; - swapType: SwapType; - assetIn: AssetWithIdAndAmount; - assetOut: AssetWithIdAndAmount; - initiatorAddr: string; - slippage: number; -}): Promise; +import { AssetWithIdAndDecimals } from "../../util/asset/assetModels"; +declare function generateTxns(params: GenerateSwapTxnsParams): Promise; declare function signTxns({ txGroup, initiatorSigner }: { txGroup: SignerTransaction[]; initiatorSigner: InitiatorSigner; @@ -20,49 +12,65 @@ declare function signTxns({ txGroup, initiatorSigner }: { /** * Executes a swap with the desired quantities. */ -declare function execute({ client, pool, txGroup, signedTxns, network, assetIn }: { +declare function execute({ client, quote, txGroup, signedTxns }: { client: Algodv2; - pool: V2PoolInfo; - network: SupportedNetwork; + quote: SwapQuote; txGroup: SignerTransaction[]; signedTxns: Uint8Array[]; - assetIn: AssetWithIdAndAmount; }): Promise; /** * @param type - Type of the swap * @param pool - Information for the pool. - * @param asset.assetID - ID of the asset to be swapped - * @param asset.amount - Amount of the asset to be swapped - * @param decimals.assetIn - Decimals quantity for the input asset - * @param decimals.assetOut - Decimals quantity for the output asset + * @param assetIn - Asset to be swapped + * @param assetOut - Asset to be received + * @param amount - Amount of asset to be swapped + * @param network - Network to be used + * @param isSwapRouterEnabled - Whether the swap router is enabled * @returns A promise for the Swap quote */ -declare function getQuote(type: SwapType, pool: V2PoolInfo, asset: AssetWithIdAndAmount, decimals: { - assetIn: number; - assetOut: number; +declare function getQuote({ type, amount, assetIn, assetOut, network, isSwapRouterEnabled, pool }: { + type: SwapType; + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; + pool: V2PoolInfo | null; + network: SupportedNetwork; + isSwapRouterEnabled?: boolean; +}): Promise; +declare function getFixedInputDirectSwapQuote({ amount, assetIn, assetOut, pool }: { + pool: V2PoolInfo; + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; +}): DirectSwapQuote; +declare function getFixedOutputDirectSwapQuote({ amount, assetIn, assetOut, pool }: { + pool: V2PoolInfo | null; + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; }): SwapQuote; /** * @returns A quote for a fixed input swap. Does NOT execute any transactions. */ -declare function getFixedInputSwapQuote({ pool, assetIn, decimals }: { - pool: V2PoolInfo; - assetIn: AssetWithIdAndAmount; - decimals: { - assetIn: number; - assetOut: number; - }; -}): SwapQuote; +declare function getFixedInputSwapQuote({ amount, assetIn, assetOut, isSwapRouterEnabled, network, pool }: { + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; + network: SupportedNetwork; + pool: V2PoolInfo | null; + isSwapRouterEnabled?: boolean; +}): Promise; /** * @returns A quote for a fixed output swap. Does NOT execute any transactions. */ -declare function getFixedOutputSwapQuote({ pool, assetOut, decimals }: { - pool: V2PoolInfo; - assetOut: AssetWithIdAndAmount; - decimals: { - assetIn: number; - assetOut: number; - }; -}): SwapQuote; +declare function getFixedOutputSwapQuote({ amount, assetIn, assetOut, isSwapRouterEnabled, network, pool }: { + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; + pool: V2PoolInfo | null; + network: SupportedNetwork; + isSwapRouterEnabled?: boolean; +}): Promise; declare function calculateFixedInputSwap({ inputSupply, outputSupply, swapInputAmount, totalFeeShare, decimals }: { inputSupply: bigint; outputSupply: bigint; @@ -80,6 +88,8 @@ declare function calculateFixedInputSwap({ inputSupply, outputSupply, swapInputA export declare const SwapV2: { getQuote: typeof getQuote; getFixedInputSwapQuote: typeof getFixedInputSwapQuote; + getFixedInputDirectSwapQuote: typeof getFixedInputDirectSwapQuote; + getFixedOutputDirectSwapQuote: typeof getFixedOutputDirectSwapQuote; getFixedOutputSwapQuote: typeof getFixedOutputSwapQuote; generateTxns: typeof generateTxns; signTxns: typeof signTxns; diff --git a/dist/swap/v2/router/constants.d.ts b/dist/swap/v2/router/constants.d.ts new file mode 100644 index 00000000..1202a2df --- /dev/null +++ b/dist/swap/v2/router/constants.d.ts @@ -0,0 +1,7 @@ +import { SupportedNetwork } from "../../../util/commonTypes"; +import { SwapType } from "../../constants"; +export declare const SWAP_ROUTER_APP_ID: Record; +/** + * Inner txn counts according to the swap type + */ +export declare const SWAP_ROUTER_INNER_TXN_COUNT: Record; diff --git a/dist/swap/v2/router/index.d.ts b/dist/swap/v2/router/index.d.ts new file mode 100644 index 00000000..05b32ead --- /dev/null +++ b/dist/swap/v2/router/index.d.ts @@ -0,0 +1,2 @@ +export * from "./swap-router"; +export * from "./util"; diff --git a/dist/swap/v2/router/swap-router.d.ts b/dist/swap/v2/router/swap-router.d.ts new file mode 100644 index 00000000..1d864361 --- /dev/null +++ b/dist/swap/v2/router/swap-router.d.ts @@ -0,0 +1,36 @@ +import algosdk, { Algodv2, Transaction } from "algosdk"; +import { SupportedNetwork } from "../../../util/commonTypes"; +import { SwapType } from "../../constants"; +import { SwapRouterResponse, SwapRoute } from "../../types"; +/** + * Generates txns that would opt in the Swap Router Application to the assets used in the swap router + */ +export declare function generateSwapRouterAssetOptInTransaction({ client, routerAppID, assetIDs, initiatorAddr }: { + client: Algodv2; + routerAppID: number; + assetIDs: number[]; + initiatorAddr: string; +}): Promise; +export declare function generateSwapRouterTxns({ initiatorAddr, client, network, swapType, route, slippage }: { + client: Algodv2; + initiatorAddr: string; + swapType: SwapType; + route: SwapRoute; + network: SupportedNetwork; + slippage: number; +}): Promise<{ + txn: algosdk.Transaction; + signers: string[]; +}[]>; +export declare function getSwapRouterAppOptInRequiredAssetIDs({ client, network, assetIDs }: { + client: Algodv2; + network: SupportedNetwork; + assetIDs: number[]; +}): Promise; +export declare function getSwapRoute({ amount, assetInID, assetOutID, swapType, network }: { + assetInID: number; + assetOutID: number; + swapType: SwapType; + amount: number | bigint; + network: SupportedNetwork; +}): Promise; diff --git a/dist/swap/v2/router/types.d.ts b/dist/swap/v2/router/types.d.ts new file mode 100644 index 00000000..de649885 --- /dev/null +++ b/dist/swap/v2/router/types.d.ts @@ -0,0 +1,14 @@ +import AlgodClient from "algosdk/dist/types/src/client/v2/algod/algod"; +import { AssetWithIdAndAmount } from "../../../util/asset/assetModels"; +import { SupportedNetwork } from "../../../util/commonTypes"; +import { SwapType } from "../../constants"; +export interface GenerateSwapRouterTxnsParams { + client: AlgodClient; + routerAppID: number; + initiatorAddr: string; + assetIn: AssetWithIdAndAmount; + assetOut: AssetWithIdAndAmount; + intermediaryAssetID: number; + swapType: SwapType; + network: SupportedNetwork; +} diff --git a/dist/swap/v2/router/util.d.ts b/dist/swap/v2/router/util.d.ts new file mode 100644 index 00000000..58f63844 --- /dev/null +++ b/dist/swap/v2/router/util.d.ts @@ -0,0 +1,23 @@ +import { SupportedNetwork } from "../../../util/commonTypes"; +import { SwapRoute } from "../../types"; +declare function getSwapRouteRate(route: SwapRoute): number; +declare function getSwapRouterAppID(network: SupportedNetwork): number; +declare function getAssetOutFromSwapRoute(route: SwapRoute): { + asset: import("../../types").SwapRouteAsset; + amount: string; +}; +declare function getAssetInFromSwapRoute(route: SwapRoute): { + asset: import("../../types").SwapRouteAsset; + amount: string; +}; +declare function getAssetInAndOutFromSwapRoute(route: SwapRoute): { + assetIn: { + asset: import("../../types").SwapRouteAsset; + amount: string; + }; + assetOut: { + asset: import("../../types").SwapRouteAsset; + amount: string; + }; +}; +export { getSwapRouteRate, getSwapRouterAppID, getAssetOutFromSwapRoute, getAssetInFromSwapRoute, getAssetInAndOutFromSwapRoute }; diff --git a/dist/swap/v2/util.d.ts b/dist/swap/v2/util.d.ts index 59c2da73..b99ee743 100644 --- a/dist/swap/v2/util.d.ts +++ b/dist/swap/v2/util.d.ts @@ -3,3 +3,12 @@ import { SwapType } from "../constants"; * @returns the total fee for the swap operation including all transactions (including inner transactions) fees */ export declare function getV2SwapTotalFee(mode: SwapType): number; +/** + * @returns the minimum possible amount of assetIn that can be used for swap in V2 pools + */ +export declare function getV2MinSwapAssetInAmount(feeRate?: number): number; +/** + * @returns true if the amount of assetIn is less than the minimum possible amount of assetIn that can be used for swap in V2 pools + */ +export declare function isSwapAssetInAmountLow(amount: number, feeRate?: number): boolean; +export declare function getSwapAppCallFeeAmount(swapType: SwapType): number; diff --git a/dist/util/asset/assetModels.d.ts b/dist/util/asset/assetModels.d.ts index 80ef5c18..5343890d 100644 --- a/dist/util/asset/assetModels.d.ts +++ b/dist/util/asset/assetModels.d.ts @@ -50,6 +50,10 @@ export interface AssetWithIdAndAmount { id: number; amount: number | bigint; } +export interface AssetWithIdAndDecimals { + id: number; + decimals: number; +} export interface AssetWithAmountAndDecimals { amount: number | bigint; decimals: number; diff --git a/dist/util/asset/assetUtils.d.ts b/dist/util/asset/assetUtils.d.ts index 4ba8e74b..4e1d9e62 100644 --- a/dist/util/asset/assetUtils.d.ts +++ b/dist/util/asset/assetUtils.d.ts @@ -25,3 +25,9 @@ export declare function sortAssetIds(asset1ID: number, asset2ID: number): number * @returns `true` if the given asset id is the ALGO asset id */ export declare function isAlgo(id: number | string): boolean; +/** + * @returns Asset id as a number + */ +export declare function getAssetId(asset: { + id: string | number; +}): number; diff --git a/dist/util/commonTypes.d.ts b/dist/util/commonTypes.d.ts index 16b19b5f..f390d4ca 100644 --- a/dist/util/commonTypes.d.ts +++ b/dist/util/commonTypes.d.ts @@ -10,6 +10,14 @@ export interface SignerTransaction { } export type InitiatorSigner = (txGroupList: SignerTransaction[][]) => Promise; export type SupportedNetwork = "testnet" | "mainnet"; +export interface TinymanApiErrorDetailShape { + [x: string]: undefined | any; +} +export interface TinymanApiErrorShape { + type: Type; + detail: TinymanApiErrorDetailShape; + fallback_message: string; +} /** * Type of the waitForConfirmation()["inner-txns"] * NOT a complete type, only the fields we need. @@ -20,9 +28,11 @@ export type TxnResponseInnerTxns = { type: TransactionType.axfer; xaid: number; aamt: number; + arcv: Uint8Array; } | { type: TransactionType.pay; amt: number; + rcv: Uint8Array; } | { /** * This is not a real txn type, only added to diff --git a/dist/util/constant.d.ts b/dist/util/constant.d.ts index 8bce945a..7e1d0084 100644 --- a/dist/util/constant.d.ts +++ b/dist/util/constant.d.ts @@ -1,3 +1,4 @@ +import { SupportedNetwork } from "./commonTypes"; export declare const MAX_SLIPPAGE_FRACTION_DIGITS = 6; export declare const DEFAULT_FEE_TXN_NOTE: Uint8Array; export declare const BASE_MINIMUM_BALANCE = 100000; @@ -9,3 +10,7 @@ export declare const MINIMUM_BALANCE_REQUIRED_PER_BYTE_SCHEMA = 50000; export declare const MINIMUM_BALANCE_REQUIRED_PER_INT_SCHEMA_VALUE = 28500; export declare const MINIMUM_ADD_LIQUIDITY_AMOUNT = 1000; export declare const DEFAULT_WAIT_FOR_CONFIRMATION_ROUNDS = 1000; +export declare const TINYMAN_ANALYTICS_API_BASE_URLS: Record; diff --git a/dist/util/error/NoAvailablePoolOrRouteError.d.ts b/dist/util/error/NoAvailablePoolOrRouteError.d.ts new file mode 100644 index 00000000..4531ac8a --- /dev/null +++ b/dist/util/error/NoAvailablePoolOrRouteError.d.ts @@ -0,0 +1,4 @@ +declare class NoAvailablePoolOrRouteError extends Error { + constructor(message?: string); +} +export default NoAvailablePoolOrRouteError; diff --git a/dist/util/error/NonExistentPoolError.d.ts b/dist/util/error/NonExistentPoolError.d.ts new file mode 100644 index 00000000..92f4f8a1 --- /dev/null +++ b/dist/util/error/NonExistentPoolError.d.ts @@ -0,0 +1,4 @@ +declare class NonExistentPoolError extends Error { + constructor(message?: string); +} +export default NonExistentPoolError; diff --git a/dist/util/error/SwapError.d.ts b/dist/util/error/SwapError.d.ts new file mode 100644 index 00000000..9c2340b3 --- /dev/null +++ b/dist/util/error/SwapError.d.ts @@ -0,0 +1,15 @@ +export declare enum SwapErrorType { + SwapRouterStaleDataError = "SwapRouterStaleDataError", + SwapRouterNoRouteError = "SwapRouterNoRouteError", + SwapRouterLowSwapAmountError = "SwapRouterLowSwapAmountError", + SwapRouterInsufficientReservesError = "SwapRouterInsufficientReservesError", + SwapRouterPoolHasNoLiquidityError = "SwapRouterPoolHasNoLiquidityError", + NoAvailablePoolError = "NoAvailablePoolError", + OutputAmountExceedsAvailableLiquidityError = "OutputAmountExceedsAvailableLiquidityError" +} +declare class SwapError extends Error { + type: SwapErrorType; + message: string; + constructor(type: SwapErrorType, message: string); +} +export default SwapError; diff --git a/dist/util/error/SwapQuoteError.d.ts b/dist/util/error/SwapQuoteError.d.ts new file mode 100644 index 00000000..aa66c9f4 --- /dev/null +++ b/dist/util/error/SwapQuoteError.d.ts @@ -0,0 +1,19 @@ +export declare enum SwapQuoteErrorType { + SwapRouterStaleDataError = "SwapRouterStaleDataError", + SwapRouterNoRouteError = "SwapRouterNoRouteError", + SwapRouterLowSwapAmountError = "SwapRouterLowSwapAmountError", + SwapRouterInsufficientReservesError = "SwapRouterInsufficientReservesError", + SwapRouterPoolHasNoLiquidityError = "SwapRouterPoolHasNoLiquidityError", + NoAvailablePoolError = "NoAvailablePoolError", + OutputAmountExceedsAvailableLiquidityError = "OutputAmountExceedsAvailableLiquidityError", + UnknownError = "UnknownError", + LowSwapAmountError = "LowSwapAmountError", + AssetDoesNotBelongToPoolError = "AssetDoesNotBelongToPoolError", + InvalidSwapTypeError = "InvalidSwapTypeError" +} +declare class SwapQuoteError extends Error { + type: SwapQuoteErrorType; + message: string; + constructor(type: SwapQuoteErrorType, message: string); +} +export default SwapQuoteError; diff --git a/dist/util/transaction/transactionUtils.d.ts b/dist/util/transaction/transactionUtils.d.ts index d24ccbd4..ac42a434 100644 --- a/dist/util/transaction/transactionUtils.d.ts +++ b/dist/util/transaction/transactionUtils.d.ts @@ -1,4 +1,4 @@ -import { Algodv2 } from "algosdk"; +import { Algodv2, Transaction } from "algosdk"; import { AssetWithIdAndAmount } from "../asset/assetModels"; import { SignerTransaction, TxnResponseInnerTxns } from "../commonTypes"; export declare function getAppCallTxnResponse(client: Algodv2, txGroup: SignerTransaction[]): Promise | undefined>; @@ -19,3 +19,9 @@ export declare function getAppCallInnerAssetData(client: Algodv2, txGroup: Signe * @returns the combined signer transaction groups, with a new assigned group ID */ export declare function combineAndRegroupSignerTxns(...signerTransactions: SignerTransaction[][]): SignerTransaction[]; +/** + * Extracts the account address from the provided transaction. + * @param txn - The transaction to extract the sender address from + * @returns the account address of the sender + */ +export declare function extractSenderAddressFromTransaction(txn: Transaction): string; diff --git a/dist/util/util.d.ts b/dist/util/util.d.ts index b1692fab..ebb53388 100644 --- a/dist/util/util.d.ts +++ b/dist/util/util.d.ts @@ -1,6 +1,6 @@ /// import { Algodv2 } from "algosdk"; -import { SignerTransaction } from "./commonTypes"; +import { SignerTransaction, TinymanApiErrorShape } from "./commonTypes"; import { AccountInformation } from "./account/accountTypes"; export declare function decodeState({ stateArray, shouldDecodeKeys }: { stateArray: AccountInformation["apps-local-state"][0]["key-value"]; @@ -56,3 +56,4 @@ export declare function encodeInteger(number: any): number[]; * Converts a text into bytes */ export declare function encodeString(text: string): Uint8Array; +export declare function hasTinymanApiErrorShape(error: any): error is TinymanApiErrorShape; diff --git a/package-lock.json b/package-lock.json index f1d41b09..d967fae8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tinymanorg/tinyman-js-sdk", - "version": "2.1.1", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@tinymanorg/tinyman-js-sdk", - "version": "2.1.1", + "version": "3.0.0", "license": "MIT", "dependencies": { "algosdk": "^2.1.0", diff --git a/package.json b/package.json index 01a33fac..889fbc5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tinymanorg/tinyman-js-sdk", - "version": "2.1.1", + "version": "3.0.0", "description": "Tinyman JS SDK", "author": "Tinyman Core Team", "license": "MIT", diff --git a/src/index.ts b/src/index.ts index 1319f4df..1a98b2b0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ +import SwapQuoteError from "./util/error/SwapQuoteError"; + export type { InitiatorSigner, SignerTransaction, @@ -13,6 +15,10 @@ export { MINIMUM_ADD_LIQUIDITY_AMOUNT } from "./util/constant"; +export * from "./swap/v2/router"; + +export * from "./swap/common/utils"; + export { applySlippageToAmount, ASSET_OPT_IN_PROCESS_TXN_COUNT, @@ -105,13 +111,20 @@ export {RemoveLiquidity} from "./remove-liquidity"; export type { SwapQuote, - SwapQuoteWithPool, V1SwapExecution, - V2SwapExecution + V2SwapExecution, + DirectSwapQuote, + SwapRoute, + GenerateSwapTxnsParams } from "./swap/types"; -export {getSwapTotalFee} from "./swap/utils"; +export * from "./swap/v2/util"; export {SwapType} from "./swap/constants"; export {Swap} from "./swap"; +// eslint-disable-next-line no-duplicate-imports +export {SwapQuoteType} from "./swap/types"; +export {SwapQuoteError}; +// eslint-disable-next-line no-duplicate-imports +export {SwapQuoteErrorType} from "./util/error/SwapQuoteError"; export { redeemExcessAsset, diff --git a/src/swap/common/utils.ts b/src/swap/common/utils.ts index 50c7e973..12ae0211 100644 --- a/src/swap/common/utils.ts +++ b/src/swap/common/utils.ts @@ -1,5 +1,21 @@ -import {AssetWithAmountAndDecimals} from "../../util/asset/assetModels"; +import {CONTRACT_VERSION} from "../../contract/constants"; +import {ContractVersionValue} from "../../contract/types"; +import { + AssetWithAmountAndDecimals, + AssetWithIdAndAmount +} from "../../util/asset/assetModels"; +import {getAssetId} from "../../util/asset/assetUtils"; +import SwapQuoteError, {SwapQuoteErrorType} from "../../util/error/SwapQuoteError"; import {convertFromBaseUnits, roundNumber} from "../../util/util"; +import {SwapType} from "../constants"; +import {SwapQuote, SwapQuoteType} from "../types"; +import {V1_1_SWAP_TOTAL_FEE} from "../v1_1/constants"; +import { + getAssetInFromSwapRoute, + getAssetOutFromSwapRoute, + getSwapRouteRate +} from "../v2/router/util"; +import {getV2SwapTotalFee} from "../v2/util"; function calculateSwapRate({ assetIn, @@ -33,4 +49,140 @@ function calculatePriceImpact({ return roundNumber({decimalPlaces: 5}, Math.abs(swapRate / poolPrice - 1)); } -export {calculateSwapRate, calculatePriceImpact}; +function getSwapQuotePriceImpact(quote: SwapQuote) { + return quote.type === SwapQuoteType.Router + ? Number(quote.data.price_impact) + : quote.data.quote.priceImpact; +} + +function getAssetInFromSwapQuote(quote: SwapQuote): AssetWithIdAndAmount { + if (quote.type === SwapQuoteType.Router) { + const assetIn = getAssetInFromSwapRoute(quote.data.route); + + return { + id: getAssetId(assetIn.asset), + amount: Number(assetIn.amount) + }; + } + + return { + id: quote.data.quote.assetInID, + amount: quote.data.quote.assetInAmount + }; +} + +function getAssetOutFromSwapQuote(quote: SwapQuote): AssetWithIdAndAmount { + if (quote.type === SwapQuoteType.Router) { + const assetOut = getAssetOutFromSwapRoute(quote.data.route); + + return { + id: getAssetId(assetOut.asset), + amount: Number(assetOut.amount) + }; + } + + return { + id: quote.data.quote.assetOutID, + amount: quote.data.quote.assetOutAmount + }; +} + +function getAssetInAndAssetOutFromSwapQuote(quote: SwapQuote): { + assetIn: AssetWithIdAndAmount; + assetOut: AssetWithIdAndAmount; +} { + return { + assetIn: getAssetInFromSwapQuote(quote), + assetOut: getAssetOutFromSwapQuote(quote) + }; +} + +function getSwapQuoteContractVersion(quote: SwapQuote): ContractVersionValue { + if (quote.type === SwapQuoteType.Direct) { + return quote.data.pool.contractVersion; + } + return CONTRACT_VERSION.V2; +} + +/** + * @returns the total fee that will be paid by the user + * for the swap transaction with given parameters + */ +function getSwapTotalFee( + params: + | { + version: typeof CONTRACT_VERSION.V1_1; + } + | { + version: typeof CONTRACT_VERSION.V2; + type: SwapType; + } +) { + switch (params.version) { + case CONTRACT_VERSION.V1_1: + return V1_1_SWAP_TOTAL_FEE; + + case CONTRACT_VERSION.V2: + return getV2SwapTotalFee(params.type); + + default: + throw new Error("Provided contract version was not valid."); + } +} + +/** + * @returns The asset amount ratio for the given quote + */ +function getSwapQuoteRate(quote: SwapQuote): number { + if (quote.type === SwapQuoteType.Direct) { + return quote.data.quote.rate; + } + + return getSwapRouteRate(quote.data.route); +} + +/** + * Compares the given quotes and returns the best one (with the highest rate). + */ +function getBestQuote(quotes: SwapQuote[]): SwapQuote { + let bestQuote: SwapQuote = quotes[0]; + let bestQuoteRate = getSwapQuoteRate(bestQuote); + + for (let index = 1; index < quotes.length; index++) { + const quote = quotes[index]; + const currentRate = getSwapQuoteRate(quote); + + if (currentRate > bestQuoteRate) { + bestQuote = quote; + bestQuoteRate = currentRate; + } + } + + return bestQuote; +} + +function isSwapQuoteErrorCausedByAmount(error: Error): boolean { + return ( + error instanceof SwapQuoteError && + [ + SwapQuoteErrorType.SwapRouterInsufficientReservesError, + SwapQuoteErrorType.SwapRouterLowSwapAmountError, + SwapQuoteErrorType.OutputAmountExceedsAvailableLiquidityError, + SwapQuoteErrorType.LowSwapAmountError + ].includes(error.type) + ); +} + +export { + calculateSwapRate, + calculatePriceImpact, + getSwapQuotePriceImpact, + getAssetInFromSwapQuote, + getAssetOutFromSwapQuote, + getAssetInAndAssetOutFromSwapQuote, + getSwapQuoteContractVersion, + getSwapTotalFee, + getSwapQuoteRate, + getBestQuote, + isSwapQuoteErrorCausedByAmount +}; diff --git a/src/swap/constants.ts b/src/swap/constants.ts index 833f5573..cc63bfb2 100644 --- a/src/swap/constants.ts +++ b/src/swap/constants.ts @@ -2,3 +2,5 @@ export enum SwapType { FixedInput = "fixed-input", FixedOutput = "fixed-output" } + +export const DEFAULT_SWAP_FEE_RATE = 0.003; diff --git a/src/swap/types.ts b/src/swap/types.ts index 5958fb46..79d60e5f 100644 --- a/src/swap/types.ts +++ b/src/swap/types.ts @@ -1,8 +1,16 @@ -import {AssetWithIdAndAmount} from "../util/asset/assetModels"; +import {Algodv2} from "algosdk"; + +import {AssetWithIdAndAmount, TinymanAnalyticsApiAsset} from "../util/asset/assetModels"; +import {SignerTransaction, SupportedNetwork} from "../util/commonTypes"; import {PoolReserves, V1PoolInfo, V2PoolInfo} from "../util/pool/poolTypes"; +import {SwapType} from "./constants"; + +export enum SwapQuoteType { + Direct = "direct", + Router = "router" +} -/** An object containing information about a swap quote. */ -export interface SwapQuote { +export interface DirectSwapQuote { /** The ID of the input asset in this quote. */ assetInID: number; /** The quantity of the input asset in this quote. */ @@ -21,6 +29,103 @@ export interface SwapQuote { round?: number; } +export interface DirectSwapQuoteAndPool { + quote: DirectSwapQuote; + pool: V1PoolInfo | V2PoolInfo; +} + +export interface SwapRouteAsset { + id: string; + name: string; + unit_name: string; + decimals: number; +} + +export interface SwapRoutePool { + address: string; + asset_1: SwapRouteAsset; + asset_2: SwapRouteAsset; + version: "2.0"; +} + +export type SwapRoute = { + quote: SwapRouterQuote; + pool: SwapRoutePool; +}[]; + +export interface SwapRouterQuote { + swap_type: SwapType; + amount_in: { + asset: SwapRouteAsset; + amount: string; + }; + amount_out: { + asset: SwapRouteAsset; + amount: string; + }; + swap_fees: { + amount: string; + asset: SwapRouteAsset; + }; + price: number; + price_impact: number; +} + +export interface FetchSwapRouteQuotesPayload { + asset_in_id: string; + asset_out_id: string; + amount: string; + swap_type: SwapType; +} + +export type SwapRouterResponse = FetchSwapRouteQuotesPayload & { + route: SwapRoute; + price_impact: string; + status: { + round_number: string; + round_datetime: string; + }; +}; + +export type GetSwapQuoteParams = { + assetIn: Pick; + assetOut: Pick; + pools: {info: V1PoolInfo | V2PoolInfo; reserves: PoolReserves}[]; + amount: number | bigint; + type: SwapType; + network: SupportedNetwork; + /** If `true`, the function will also check the quotes that use swap route */ + isSwapRouterEnabled?: boolean; +}; + +export type SwapQuote = + | { + data: DirectSwapQuoteAndPool; + type: SwapQuoteType.Direct; + } + | { + data: SwapRouterResponse; + type: SwapQuoteType.Router; + }; + +export type GetSwapQuoteBySwapTypeParams = Omit; + +export interface GenerateSwapTxnsParams { + client: Algodv2; + network: SupportedNetwork; + quote: SwapQuote; + swapType: SwapType; + slippage: number; + initiatorAddr: string; +} + +export type GenerateV1_1SwapTxnsParams = Omit< + GenerateSwapTxnsParams, + "quote" | "network" +> & { + quoteAndPool: DirectSwapQuoteAndPool; +}; + /** An object containing information about a successfully executed swap. */ export interface V1SwapExecution { /** The round that the swap occurred in. */ @@ -57,12 +162,13 @@ export interface V2SwapExecution { /** Can be `undefined` if the execution was successful, but there was an issue while * extracting the output asset data from the transaction response */ assetOut: AssetWithIdAndAmount | undefined; - pool: V2PoolInfo; + quote: SwapQuote; txnID: string; round: number; } -export interface SwapQuoteWithPool { - quote: SwapQuote; - pool: {info: V1PoolInfo | V2PoolInfo; reserves: PoolReserves}; +export interface ExecuteSwapCommonParams { + client: Algodv2; + txGroup: SignerTransaction[]; + signedTxns: Uint8Array[]; } diff --git a/src/swap/utils.ts b/src/swap/utils.ts index 5ba5702f..602aadd9 100644 --- a/src/swap/utils.ts +++ b/src/swap/utils.ts @@ -1,38 +1,38 @@ -import {Algodv2} from "algosdk"; - import {CONTRACT_VERSION} from "../contract/constants"; -import {AssetWithIdAndAmount, TinymanAnalyticsApiAsset} from "../util/asset/assetModels"; -import {InitiatorSigner, SignerTransaction, SupportedNetwork} from "../util/commonTypes"; -import {PoolReserves, V1PoolInfo, V2PoolInfo} from "../util/pool/poolTypes"; -import {SwapQuoteWithPool, SwapQuote} from "./types"; +import {InitiatorSigner, SignerTransaction} from "../util/commonTypes"; +import {V1PoolInfo} from "../util/pool/poolTypes"; +import { + GetSwapQuoteBySwapTypeParams, + GenerateSwapTxnsParams, + GetSwapQuoteParams, + SwapQuote, + SwapQuoteType, + ExecuteSwapCommonParams +} from "./types"; import {SwapType} from "./constants"; import {SwapV1_1} from "./v1_1"; import {SwapV2} from "./v2"; -import {V1_1_SWAP_TOTAL_FEE} from "./v1_1/constants"; -import {getV2SwapTotalFee} from "./v2/util"; -import {isPoolEmpty} from "../util/pool/common"; -import OutputAmountExceedsAvailableLiquidityError from "../util/error/OutputAmountExceedsAvailableLiquidityError"; +import { + getBestQuote, + getSwapQuoteContractVersion, + isSwapQuoteErrorCausedByAmount +} from "./common/utils"; +import {getAssetId} from "../util/asset/assetUtils"; +import SwapQuoteError, {SwapQuoteErrorType} from "../util/error/SwapQuoteError"; /** - * Gets quotes for swap from each pool passed as an argument, - * and returns the best quote (with the highest rate). + * Gets the best quote for swap from the pools and swap router and returns the best option. */ -export function getQuote(params: { - type: SwapType; - pools: {info: V1PoolInfo | V2PoolInfo; reserves: PoolReserves}[]; - assetIn: Pick; - assetOut: Pick; - amount: number | bigint; -}): Promise { - if (params.pools.every((pool) => isPoolEmpty(pool.reserves))) { - throw new Error("No pools available for swap"); - } +export function getQuote(params: GetSwapQuoteParams): Promise { + const {type} = params; - if (params.type === SwapType.FixedInput) { + if (type === SwapType.FixedInput) { return getFixedInputSwapQuote(params); + } else if (type === SwapType.FixedOutput) { + return getFixedOutputSwapQuote(params); } - return getFixedOutputSwapQuote(params); + throw new SwapQuoteError(SwapQuoteErrorType.InvalidSwapTypeError, "Invalid swap type"); } /** @@ -40,67 +40,94 @@ export function getQuote(params: { * Validity of the quote is checked by if the promise was successfully resolved * and an actual quote object is available on the response */ -function validateQuotes( - promises: Promise[] -): Promise { +function validateQuotes(promises: Promise[]): Promise { return Promise.allSettled(promises).then((results) => { - if ( - results.every( - (result) => - result.status === "rejected" && - result.reason instanceof OutputAmountExceedsAvailableLiquidityError - ) - ) { - throw new OutputAmountExceedsAvailableLiquidityError(); + if (results.every((result) => result.status === "rejected")) { + const [v1_1PoolError, v2PoolError] = (results as PromiseRejectedResult[]).map( + (result) => result.reason + ) as SwapQuoteError[]; + + if ( + isSwapQuoteErrorCausedByAmount(v1_1PoolError) && + !isSwapQuoteErrorCausedByAmount(v2PoolError) + ) { + throw v1_1PoolError; + } + + throw v2PoolError; } - return ( + const filteredResults = ( results.filter( - (result) => result.status === "fulfilled" && result.value.quote !== undefined - ) as PromiseFulfilledResult[] + (result) => result.status === "fulfilled" && result.value + ) as PromiseFulfilledResult[] ).map((result) => result.value); + + return filteredResults; }); } /** - * Gets quotes for fixed input swap from each pool passed as an argument, + * Gets quotes for fixed input swap the pools and swap router, * and returns the best quote (with the highest rate). */ -export async function getFixedInputSwapQuote({ - pools, - assetIn, - assetOut, - amount -}: { - pools: {info: V1PoolInfo | V2PoolInfo; reserves: PoolReserves}[]; - assetIn: Pick; - assetOut: Pick; - amount: number | bigint; -}): Promise { - const quotePromises = pools.map>((pool) => { - return new Promise((resolve, reject) => { - let quote: SwapQuote | undefined; - - const quoteGetterArgs = { - pool: pool.info, - assetIn: {amount, id: Number(assetIn.id)}, - decimals: {assetIn: assetIn.decimals, assetOut: assetOut.decimals}, - reserves: pool.reserves - }; - - try { - if (pool.info.contractVersion === CONTRACT_VERSION.V1_1) { - quote = SwapV1_1.getFixedInputSwapQuote(quoteGetterArgs); - } else { - quote = SwapV2.getFixedInputSwapQuote(quoteGetterArgs); +export async function getFixedInputSwapQuote( + params: GetSwapQuoteBySwapTypeParams +): Promise { + const {amount, assetIn, assetOut, isSwapRouterEnabled, pools} = params; + + const quotePromises: Promise[] = []; + + const v1_1Pool = pools.find( + (pool) => pool.info.contractVersion === CONTRACT_VERSION.V1_1 + ); + + if (v1_1Pool) { + quotePromises.push( + new Promise((resolve, reject) => { + try { + resolve( + SwapV1_1.getFixedInputSwapQuote({ + pool: v1_1Pool.info, + assetIn: {amount, id: Number(assetIn.id)}, + decimals: {assetIn: assetIn.decimals, assetOut: assetOut.decimals}, + reserves: v1_1Pool.reserves + }) + ); + } catch (error) { + reject(error); } + }) + ); + } else { + quotePromises.push( + Promise.reject( + new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "Trying to swap from non-existent pool" + ) + ) + ); + } - resolve({pool, quote}); - } catch (error) { - reject(error); - } - }); - }); + const v2Pool = pools.find((pool) => pool.info.contractVersion === CONTRACT_VERSION.V2); + + quotePromises.push( + SwapV2.getFixedInputSwapQuote({ + amount, + assetIn: { + id: getAssetId(assetIn), + decimals: assetIn.decimals + }, + assetOut: { + id: getAssetId(assetOut), + decimals: assetOut.decimals + }, + pool: v2Pool?.info ?? null, + isSwapRouterEnabled, + network: params.network + }) + ); const validQuotes = await validateQuotes(quotePromises); @@ -108,106 +135,115 @@ export async function getFixedInputSwapQuote({ } /** - * Gets quotes for fixed output swap from each pool passed as an argument, + * Gets quotes for fixed output swap from the pools and swap router, * and returns the best quote (with the highest rate). */ -export async function getFixedOutputSwapQuote({ - pools, - assetIn, - assetOut, - amount -}: { - pools: {info: V1PoolInfo | V2PoolInfo; reserves: PoolReserves}[]; - assetIn: Pick; - assetOut: Pick; - amount: number | bigint; -}): Promise { - const quotePromises = pools.map>((pool) => { - return new Promise((resolve, reject) => { - let quote: SwapQuote | undefined; - - const quoteGetterArgs = { - pool: pool.info, - assetOut: {amount, id: Number(assetOut.id)}, - decimals: {assetIn: assetIn.decimals, assetOut: assetOut.decimals}, - reserves: pool.reserves - }; - - try { - if (pool.info.contractVersion === CONTRACT_VERSION.V1_1) { - quote = SwapV1_1.getFixedOutputSwapQuote(quoteGetterArgs); - } else { - quote = SwapV2.getFixedOutputSwapQuote(quoteGetterArgs); +export async function getFixedOutputSwapQuote( + params: GetSwapQuoteBySwapTypeParams +): Promise { + const {amount, assetIn, assetOut, pools, isSwapRouterEnabled} = params; + + const quotePromises: Promise[] = []; + + const v1_1Pool = pools.find( + (pool) => pool.info.contractVersion === CONTRACT_VERSION.V1_1 + ); + + if (v1_1Pool) { + quotePromises.push( + new Promise((resolve, reject) => { + try { + resolve( + SwapV1_1.getFixedOutputSwapQuote({ + pool: v1_1Pool.info, + assetOut: {amount, id: Number(assetOut.id)}, + decimals: {assetIn: assetIn.decimals, assetOut: assetOut.decimals}, + reserves: v1_1Pool.reserves + }) + ); + } catch (error) { + reject(error); } + }) + ); + } else { + quotePromises.push( + Promise.reject( + new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "Trying to swap from non-existent pool" + ) + ) + ); + } - resolve({pool, quote}); - } catch (error) { - reject(error); - } - }); - }); + const v2Pool = pools.find((pool) => pool.info.contractVersion === CONTRACT_VERSION.V2); + + quotePromises.push( + SwapV2.getFixedOutputSwapQuote({ + amount, + assetIn: { + id: getAssetId(assetIn), + decimals: assetIn.decimals + }, + assetOut: { + id: getAssetId(assetOut), + decimals: assetOut.decimals + }, + pool: v2Pool?.info ?? null, + isSwapRouterEnabled, + network: params.network + }) + ); const validQuotes = await validateQuotes(quotePromises); return getBestQuote(validQuotes); } -/** - * Compares the given quotes and returns the best one (with the highest rate). - */ -function getBestQuote(quotes: SwapQuoteWithPool[]): SwapQuoteWithPool { - const quotesByDescendingRate = quotes - .filter((quote) => !isPoolEmpty(quote.pool.reserves)) - .sort((a, b) => b.quote.rate - a.quote.rate); - - return quotesByDescendingRate[0]; -} - -export function generateTxns(params: { - client: Algodv2; - pool: V1PoolInfo | V2PoolInfo; - poolAddress: string; - swapType: SwapType; - assetIn: AssetWithIdAndAmount; - assetOut: AssetWithIdAndAmount; - slippage: number; - initiatorAddr: string; -}): Promise { - if (params.pool.contractVersion === CONTRACT_VERSION.V1_1) { - return SwapV1_1.generateTxns(params); +export function generateTxns( + params: GenerateSwapTxnsParams +): Promise { + if ( + params.quote.type === SwapQuoteType.Direct && + getSwapQuoteContractVersion(params.quote) === CONTRACT_VERSION.V1_1 + ) { + return SwapV1_1.generateTxns({...params, quoteAndPool: params.quote.data}); } return SwapV2.generateTxns(params); } export function signTxns(params: { - pool: V1PoolInfo; + quote: SwapQuote; txGroup: SignerTransaction[]; initiatorSigner: InitiatorSigner; }): Promise { - if (params.pool.contractVersion === CONTRACT_VERSION.V1_1) { - return SwapV1_1.signTxns(params); + if ( + params.quote.type === SwapQuoteType.Direct && + getSwapQuoteContractVersion(params.quote) === CONTRACT_VERSION.V1_1 + ) { + const { + data: {pool} + } = params.quote; + + return SwapV1_1.signTxns({...params, pool}); } return SwapV2.signTxns(params); } -interface ExecuteCommonParams { - swapType: SwapType; - client: Algodv2; - pool: V2PoolInfo; - network: SupportedNetwork; - txGroup: SignerTransaction[]; - signedTxns: Uint8Array[]; - assetIn: AssetWithIdAndAmount; -} - export function execute( params: ( - | {contractVersion: typeof CONTRACT_VERSION.V1_1; initiatorAddr: string} - | {contractVersion: typeof CONTRACT_VERSION.V2} + | { + contractVersion: typeof CONTRACT_VERSION.V1_1; + initiatorAddr: string; + pool: V1PoolInfo; + swapType: SwapType; + } + | {contractVersion: typeof CONTRACT_VERSION.V2; quote: SwapQuote} ) & - ExecuteCommonParams + ExecuteSwapCommonParams ) { if (params.contractVersion === CONTRACT_VERSION.V1_1) { return SwapV1_1.execute(params); @@ -215,29 +251,3 @@ export function execute( return SwapV2.execute(params); } - -/** - * @returns the total fee that will be paid by the user - * for the swap transaction with given parameters - */ -export function getSwapTotalFee( - params: - | { - version: typeof CONTRACT_VERSION.V1_1; - } - | { - version: typeof CONTRACT_VERSION.V2; - type: SwapType; - } -) { - switch (params.version) { - case CONTRACT_VERSION.V1_1: - return V1_1_SWAP_TOTAL_FEE; - - case CONTRACT_VERSION.V2: - return getV2SwapTotalFee(params.type); - - default: - throw new Error("Provided contract version was not valid."); - } -} diff --git a/src/swap/v1_1/index.ts b/src/swap/v1_1/index.ts index 24a8e9a5..d9083422 100644 --- a/src/swap/v1_1/index.ts +++ b/src/swap/v1_1/index.ts @@ -15,13 +15,19 @@ import {DEFAULT_FEE_TXN_NOTE} from "../../util/constant"; import {ALGO_ASSET_ID} from "../../util/asset/assetConstants"; import {PoolReserves, PoolStatus, V1PoolInfo} from "../../util/pool/poolTypes"; import {getAccountExcessWithinPool} from "../../util/account/accountUtils"; -import {SwapQuote, V1SwapExecution} from "../types"; +import { + DirectSwapQuote, + GenerateV1_1SwapTxnsParams, + SwapQuote, + SwapQuoteType, + V1SwapExecution +} from "../types"; import {SwapType} from "../constants"; import {calculatePriceImpact, calculateSwapRate} from "../common/utils"; -import OutputAmountExceedsAvailableLiquidityError from "../../util/error/OutputAmountExceedsAvailableLiquidityError"; import {AssetWithIdAndAmount} from "../../util/asset/assetModels"; import {tinymanJSSDKConfig} from "../../config"; import {CONTRACT_VERSION} from "../../contract/constants"; +import SwapQuoteError, {SwapQuoteErrorType} from "../../util/error/SwapQuoteError"; // FEE = %0.3 or 3/1000 const FEE_NUMERATOR = 3n; @@ -62,32 +68,25 @@ async function signTxns({ async function generateTxns({ client, - pool, + quoteAndPool, swapType, - assetIn, - assetOut, slippage, initiatorAddr -}: { - client: Algodv2; - pool: V1PoolInfo; - swapType: SwapType; - assetIn: AssetWithIdAndAmount; - assetOut: AssetWithIdAndAmount; - slippage: number; - initiatorAddr: string; -}): Promise { +}: GenerateV1_1SwapTxnsParams): Promise { + const {pool, quote} = quoteAndPool; + const {assetInID, assetOutID} = quote; + const poolAddress = pool.account.address(); const poolAssets = [pool.asset1ID, pool.asset2ID]; if ( - !poolAssets.includes(assetIn.id) || - !poolAssets.includes(assetOut.id) || - assetIn.id === assetOut.id + !poolAssets.includes(assetInID) || + !poolAssets.includes(assetOutID) || + assetInID === assetOutID ) { throw new TinymanError( - {pool, assetIn, assetOut}, - `Input asset (#${assetIn.id}) and output asset (#${assetOut.id}) provided to generate transactions do not belong to the pool ${poolAddress}.` + {pool, quote}, + `Input asset (#${assetInID}) and output asset (#${assetOutID}) provided to generate transactions do not belong to the pool ${poolAddress}.` ); } @@ -112,11 +111,11 @@ async function generateTxns({ const assetInAmount = swapType === SwapType.FixedOutput - ? applySlippageToAmount("positive", slippage, assetIn.amount) - : assetIn.amount; + ? applySlippageToAmount("positive", slippage, quote.assetInAmount) + : quote.assetInAmount; let assetInTxn: algosdk.Transaction; - if (assetIn.id === ALGO_ASSET_ID) { + if (assetInID === ALGO_ASSET_ID) { assetInTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ from: initiatorAddr, to: poolAddress, @@ -127,7 +126,7 @@ async function generateTxns({ assetInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ from: initiatorAddr, to: poolAddress, - assetIndex: assetIn.id, + assetIndex: assetInID, amount: assetInAmount, suggestedParams }); @@ -135,11 +134,11 @@ async function generateTxns({ const assetOutAmount = swapType === SwapType.FixedInput - ? applySlippageToAmount("negative", slippage, assetOut.amount) - : assetOut.amount; + ? applySlippageToAmount("negative", slippage, quote.assetOutAmount) + : quote.assetOutAmount; let assetOutTxn: algosdk.Transaction; - if (assetOut.id === ALGO_ASSET_ID) { + if (assetOutID === ALGO_ASSET_ID) { assetOutTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ from: poolAddress, to: initiatorAddr, @@ -150,7 +149,7 @@ async function generateTxns({ assetOutTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ from: poolAddress, to: initiatorAddr, - assetIndex: assetOut.id, + assetIndex: assetOutID, amount: assetOutAmount, suggestedParams }); @@ -197,7 +196,7 @@ function getQuote( asset: AssetWithIdAndAmount, decimals: {assetIn: number; assetOut: number} ): SwapQuote { - let quote; + let quote: SwapQuote; if (type === SwapType.FixedInput) { quote = getFixedInputSwapQuote({pool, reserves, assetIn: asset, decimals}); @@ -229,7 +228,10 @@ function getFixedInputSwapQuote({ decimals: {assetIn: number; assetOut: number}; }): SwapQuote { if (pool.status !== PoolStatus.READY) { - throw new TinymanError({pool, assetIn}, "Trying to swap on a non-existent pool"); + throw new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "There is not an available pool for this asset pair" + ); } const assetInAmount = BigInt(assetIn.amount); @@ -247,8 +249,8 @@ function getFixedInputSwapQuote({ inputSupply = reserves.asset2; outputSupply = reserves.asset1; } else { - throw new TinymanError( - {pool, assetIn}, + throw new SwapQuoteError( + SwapQuoteErrorType.AssetDoesNotBelongToPoolError, `Input asset (#${assetIn.id}) doesn't belong to the pool ${pool.account.address()}.` ); } @@ -260,7 +262,10 @@ function getFixedInputSwapQuote({ const assetOutAmount = outputSupply - k / (inputSupply + assetInAmountMinusFee); if (assetOutAmount > outputSupply) { - throw new OutputAmountExceedsAvailableLiquidityError(); + throw new SwapQuoteError( + SwapQuoteErrorType.OutputAmountExceedsAvailableLiquidityError, + "Output amount exceeds available liquidity." + ); } const assetDataForSwapUtils = { @@ -268,7 +273,7 @@ function getFixedInputSwapQuote({ assetOut: {amount: assetOutAmount, decimals: decimals.assetOut} }; - return { + const directSwapQuote: DirectSwapQuote = { round: reserves.round, assetInID: assetIn.id, assetInAmount, @@ -282,6 +287,14 @@ function getFixedInputSwapQuote({ ...assetDataForSwapUtils }) }; + + return { + type: SwapQuoteType.Direct, + data: { + pool, + quote: directSwapQuote + } + }; } /** @@ -380,7 +393,10 @@ function getFixedOutputSwapQuote({ decimals: {assetIn: number; assetOut: number}; }): SwapQuote { if (pool.status !== PoolStatus.READY) { - throw new TinymanError({pool, assetOut}, "Trying to swap on a non-existent pool"); + throw new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "There is not an available pool for this asset pair" + ); } const assetOutAmount = BigInt(assetOut.amount); @@ -398,8 +414,8 @@ function getFixedOutputSwapQuote({ inputSupply = reserves.asset1; outputSupply = reserves.asset2; } else { - throw new TinymanError( - {pool, assetOut}, + throw new SwapQuoteError( + SwapQuoteErrorType.AssetDoesNotBelongToPoolError, `Output asset (#${ assetOut.id }) doesn't belong to the pool ${pool.account.address()}.` @@ -407,7 +423,10 @@ function getFixedOutputSwapQuote({ } if (assetOutAmount > outputSupply) { - throw new OutputAmountExceedsAvailableLiquidityError(); + throw new SwapQuoteError( + SwapQuoteErrorType.OutputAmountExceedsAvailableLiquidityError, + "Output amount exceeds available liquidity." + ); } const k = inputSupply * outputSupply; @@ -427,7 +446,7 @@ function getFixedOutputSwapQuote({ const priceImpact = roundNumber({decimalPlaces: 5}, Math.abs(rate / poolPrice - 1)); - return { + const directSwapQuote: DirectSwapQuote = { round: reserves.round, assetInID, assetInAmount, @@ -437,6 +456,14 @@ function getFixedOutputSwapQuote({ rate, priceImpact }; + + return { + type: SwapQuoteType.Direct, + data: { + pool, + quote: directSwapQuote + } + }; } /** @@ -550,7 +577,7 @@ async function execute({ if (pool.status !== PoolStatus.READY) { throw new TinymanError( {pool, swapType, txGroup}, - "Trying to swap on a non-existent pool" + "There is not an available pool for this asset pair" ); } diff --git a/src/swap/v2/constants.ts b/src/swap/v2/constants.ts index 011b6083..90a77f91 100644 --- a/src/swap/v2/constants.ts +++ b/src/swap/v2/constants.ts @@ -25,3 +25,7 @@ export const V2_SWAP_APP_CALL_SWAP_TYPE_ARGS_ENCODED = { [SwapType.FixedInput]: encodeString("fixed-input"), [SwapType.FixedOutput]: encodeString("fixed-output") } as const; + +export const V2_SWAP_ROUTER_APP_ARGS_ENCODED = { + ASSET_OPT_IN: encodeString("asset_opt_in") +} as const; diff --git a/src/swap/v2/index.ts b/src/swap/v2/index.ts index 86d4668c..423aec77 100644 --- a/src/swap/v2/index.ts +++ b/src/swap/v2/index.ts @@ -1,4 +1,4 @@ -import algosdk, {Algodv2, ALGORAND_MIN_TX_FEE, Transaction} from "algosdk"; +import algosdk, {Algodv2, Transaction} from "algosdk"; import { applySlippageToAmount, @@ -11,65 +11,75 @@ import { SupportedNetwork } from "../../util/commonTypes"; import TinymanError from "../../util/error/TinymanError"; -import {PoolStatus, V2PoolInfo} from "../../util/pool/poolTypes"; -import {SwapQuote, V2SwapExecution} from "../types"; +import {V2PoolInfo} from "../../util/pool/poolTypes"; +import { + DirectSwapQuote, + GenerateSwapTxnsParams, + SwapQuote, + SwapQuoteType, + V2SwapExecution +} from "../types"; import {SwapType} from "../constants"; import { V2_SWAP_APP_CALL_ARG_ENCODED, V2_SWAP_APP_CALL_SWAP_TYPE_ARGS_ENCODED, - V2SwapTxnGroupIndices, - V2_SWAP_APP_CALL_INNER_TXN_COUNT + V2SwapTxnGroupIndices } from "./constants"; -import {poolUtils} from "../../util/pool"; import {isAlgo} from "../../util/asset/assetUtils"; -import {calculatePriceImpact} from "../common/utils"; +import { + calculatePriceImpact, + getAssetInFromSwapQuote, + getAssetOutFromSwapQuote, + getBestQuote, + isSwapQuoteErrorCausedByAmount +} from "../common/utils"; import {getAppCallInnerAssetData} from "../../util/transaction/transactionUtils"; -import OutputAmountExceedsAvailableLiquidityError from "../../util/error/OutputAmountExceedsAvailableLiquidityError"; -import {AssetWithIdAndAmount} from "../../util/asset/assetModels"; +import {AssetWithIdAndAmount, AssetWithIdAndDecimals} from "../../util/asset/assetModels"; import {tinymanJSSDKConfig} from "../../config"; import {CONTRACT_VERSION} from "../../contract/constants"; +import {generateSwapRouterTxns, getSwapRoute} from "./router/swap-router"; +import {poolUtils} from "../../util/pool"; +import SwapQuoteError, {SwapQuoteErrorType} from "../../util/error/SwapQuoteError"; +import {getSwapAppCallFeeAmount, isSwapAssetInAmountLow} from "./util"; + +async function generateTxns( + params: GenerateSwapTxnsParams +): Promise { + if (params.quote.type === SwapQuoteType.Router) { + return generateSwapRouterTxns({...params, route: params.quote.data.route}); + } + + const {client, initiatorAddr, slippage, swapType, quote} = params; + + const { + data: {pool, quote: swapQuote} + } = quote; + const {assetInID, assetOutID} = swapQuote; -async function generateTxns({ - client, - pool, - swapType, - assetIn, - assetOut, - initiatorAddr, - slippage -}: { - client: Algodv2; - pool: V2PoolInfo; - swapType: SwapType; - assetIn: AssetWithIdAndAmount; - assetOut: AssetWithIdAndAmount; - initiatorAddr: string; - slippage: number; -}): Promise { const poolAddress = pool.account.address(); const poolAssets = [pool.asset1ID, pool.asset2ID]; if ( - !poolAssets.includes(assetIn.id) || - !poolAssets.includes(assetOut.id) || - assetIn.id === assetOut.id + !poolAssets.includes(assetInID) || + !poolAssets.includes(assetOutID) || + assetInID === assetOutID ) { throw new TinymanError( - {pool, assetIn, assetOut}, - `Input asset (#${assetIn.id}) and output asset (#${assetOut.id}) provided to generate transactions do not belong to the pool ${poolAddress}.` + {pool, quote}, + `Input asset (#${assetInID}) and output asset (#${assetOutID}) provided to generate transactions do not belong to the pool ${poolAddress}.` ); } const suggestedParams = await client.getTransactionParams().do(); - const isAssetInAlgo = isAlgo(assetIn.id); + const isAssetInAlgo = isAlgo(assetInID); const assetInAmount = swapType === SwapType.FixedInput - ? assetIn.amount - : applySlippageToAmount("positive", slippage, assetIn.amount); + ? swapQuote.assetInAmount + : applySlippageToAmount("positive", slippage, swapQuote.assetInAmount); const assetOutAmount = swapType === SwapType.FixedOutput - ? assetOut.amount - : applySlippageToAmount("negative", slippage, assetOut.amount); + ? swapQuote.assetOutAmount + : applySlippageToAmount("negative", slippage, swapQuote.assetOutAmount); /** * If the input asset is Algo, a payment txn, otherwise an asset transfer txn is required @@ -85,13 +95,13 @@ async function generateTxns({ from: initiatorAddr, to: poolAddress, amount: assetInAmount, - assetIndex: assetIn.id, + assetIndex: assetInID, suggestedParams }); const appCallTxn = algosdk.makeApplicationNoOpTxnFromObject({ from: initiatorAddr, - appIndex: pool.validatorAppID!, + appIndex: pool.validatorAppID, appArgs: [ V2_SWAP_APP_CALL_ARG_ENCODED, V2_SWAP_APP_CALL_SWAP_TYPE_ARGS_ENCODED[swapType], @@ -134,33 +144,23 @@ function signTxns({ return initiatorSigner([txGroup]); } -function getSwapAppCallFeeAmount(swapType: SwapType) { - // Add +1 to account for the outer txn fee - const totalTxnCount = V2_SWAP_APP_CALL_INNER_TXN_COUNT[swapType] + 1; - - return totalTxnCount * ALGORAND_MIN_TX_FEE; -} - /** * Executes a swap with the desired quantities. */ async function execute({ client, - pool, + quote, txGroup, - signedTxns, - network, - assetIn + signedTxns }: { client: Algodv2; - pool: V2PoolInfo; - network: SupportedNetwork; + quote: SwapQuote; txGroup: SignerTransaction[]; signedTxns: Uint8Array[]; - assetIn: AssetWithIdAndAmount; }): Promise { const [{confirmedRound, txnID}] = await sendAndWaitRawTransaction(client, [signedTxns]); - const assetOutId = [pool.asset1ID, pool.asset2ID].filter((id) => id !== assetIn.id)[0]; + const assetOutId = getAssetOutFromSwapQuote(quote).id; + const assetIn = getAssetInFromSwapQuote(quote); let innerTxnAssetData: AssetWithIdAndAmount[] | undefined; try { @@ -189,12 +189,7 @@ async function execute({ id: assetIn.id }, assetOut, - pool: await poolUtils.v2.getPoolInfo({ - client, - network, - asset1ID: pool.asset1ID, - asset2ID: pool.asset2ID - }), + quote, txnID }; } @@ -202,64 +197,129 @@ async function execute({ /** * @param type - Type of the swap * @param pool - Information for the pool. - * @param asset.assetID - ID of the asset to be swapped - * @param asset.amount - Amount of the asset to be swapped - * @param decimals.assetIn - Decimals quantity for the input asset - * @param decimals.assetOut - Decimals quantity for the output asset + * @param assetIn - Asset to be swapped + * @param assetOut - Asset to be received + * @param amount - Amount of asset to be swapped + * @param network - Network to be used + * @param isSwapRouterEnabled - Whether the swap router is enabled * @returns A promise for the Swap quote */ -function getQuote( - type: SwapType, - pool: V2PoolInfo, - asset: AssetWithIdAndAmount, - decimals: {assetIn: number; assetOut: number} -): SwapQuote { +async function getQuote({ + type, + amount, + assetIn, + assetOut, + network, + isSwapRouterEnabled, + pool +}: { + type: SwapType; + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; + pool: V2PoolInfo | null; + network: SupportedNetwork; + isSwapRouterEnabled?: boolean; +}): Promise { let quote: SwapQuote; if (type === SwapType.FixedInput) { - quote = getFixedInputSwapQuote({pool, assetIn: asset, decimals}); + quote = await getFixedInputSwapQuote({ + assetIn, + assetOut, + amount, + isSwapRouterEnabled, + network, + pool + }); } else { - quote = getFixedOutputSwapQuote({pool, assetOut: asset, decimals}); + quote = await getFixedOutputSwapQuote({ + amount, + assetIn, + assetOut, + isSwapRouterEnabled, + network, + pool + }); } return quote; } -/** - * @returns A quote for a fixed input swap. Does NOT execute any transactions. - */ -function getFixedInputSwapQuote({ - pool, +function validateQuotes(quotePromises: Promise[]): Promise { + return Promise.allSettled(quotePromises).then((results) => { + if (results.every((result) => result.status === "rejected")) { + const directQuoteError = (results[0] as PromiseRejectedResult) + .reason as SwapQuoteError; + + // If all promises are rejected and there are 2 of them, it means that both direct and router quotes failed. + // In this case, if the direct quote failed because of an OutputAmountExceedsAvailableLiquidityError and the router quote failed because of a SwapRouterRouteError, + // we want to throw OutputAmountExceedsAvailableLiquidityError error instead of the SwapRouterRouteError. Otherwise, we want to throw the error from swap router. + if (results.length === 2) { + const routerQuoteError = (results[1] as PromiseRejectedResult) + .reason as SwapQuoteError; + + if ( + isSwapQuoteErrorCausedByAmount(directQuoteError) && + !isSwapQuoteErrorCausedByAmount(routerQuoteError) + ) { + throw directQuoteError; + } + + throw routerQuoteError; + } + + // Otherwise, we want to throw the error from the direct quote. + throw directQuoteError; + } + + return ( + results.filter( + (result) => result.status === "fulfilled" && result.value + ) as PromiseFulfilledResult[] + ).map((result) => result.value); + }); +} + +function getFixedInputDirectSwapQuote({ + amount, assetIn, - decimals + assetOut, + pool }: { pool: V2PoolInfo; - assetIn: AssetWithIdAndAmount; - decimals: {assetIn: number; assetOut: number}; -}): SwapQuote { - if (pool.status !== PoolStatus.READY) { - throw new TinymanError({pool, assetIn}, "Trying to swap on a non-existent pool"); + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; +}): DirectSwapQuote { + if (!poolUtils.isPoolReady(pool)) { + throw new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "There is not an available pool for this asset pair" + ); } - const assetInAmount = BigInt(assetIn.amount); + const [ + {id: assetInID, decimals: assetInDecimals}, + {id: assetOutID, decimals: assetOutDecimals} + ] = [assetIn, assetOut]; + + const assetInAmount = BigInt(amount); const totalFeeShare = pool.totalFeeShare!; - let assetOutID: number; let inputSupply: bigint; let outputSupply: bigint; - if (assetIn.id === pool.asset1ID) { - assetOutID = pool.asset2ID; + if (assetInID === pool.asset1ID) { inputSupply = pool.asset1Reserves!; outputSupply = pool.asset2Reserves!; - } else if (assetIn.id === pool.asset2ID) { - assetOutID = pool.asset1ID; + } else if (assetInID === pool.asset2ID) { inputSupply = pool.asset2Reserves!; outputSupply = pool.asset1Reserves!; } else { - throw new TinymanError( - {pool, assetIn}, - `Input asset (#${assetIn.id}) doesn't belong to the pool ${pool.account.address()}.` + throw new SwapQuoteError( + SwapQuoteErrorType.AssetDoesNotBelongToPoolError, + `Input asset (#${assetInID}) doesn't belong to the pool ${pool.account.address()}.` ); } @@ -268,62 +328,77 @@ function getFixedInputSwapQuote({ outputSupply, swapInputAmount: assetInAmount, totalFeeShare, - decimals + decimals: { + assetIn: assetInDecimals, + assetOut: assetOutDecimals + } }); if (swapOutputAmount > outputSupply) { - throw new OutputAmountExceedsAvailableLiquidityError(); + throw new SwapQuoteError( + SwapQuoteErrorType.OutputAmountExceedsAvailableLiquidityError, + "Output amount exceeds available liquidity." + ); + } + + if (isSwapAssetInAmountLow(Number(amount))) { + throw new SwapQuoteError( + SwapQuoteErrorType.LowSwapAmountError, + "Swap amount is too low." + ); } return { - assetInID: assetIn.id, + assetInID, assetInAmount, assetOutID, assetOutAmount: swapOutputAmount, swapFee: Number(totalFeeAmount), rate: - convertFromBaseUnits(decimals.assetOut, Number(swapOutputAmount)) / - convertFromBaseUnits(decimals.assetIn, Number(assetInAmount)), + convertFromBaseUnits(assetOutDecimals, Number(swapOutputAmount)) / + convertFromBaseUnits(assetInDecimals, Number(assetInAmount)), priceImpact }; } -/** - * @returns A quote for a fixed output swap. Does NOT execute any transactions. - */ -function getFixedOutputSwapQuote({ - pool, +function getFixedOutputDirectSwapQuote({ + amount, + assetIn, assetOut, - decimals + pool }: { - pool: V2PoolInfo; - assetOut: AssetWithIdAndAmount; - decimals: {assetIn: number; assetOut: number}; + pool: V2PoolInfo | null; + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; }): SwapQuote { - if (pool.status !== PoolStatus.READY) { - throw new TinymanError({pool, assetOut}, "Trying to swap on a non-existent pool"); + if (!pool || !poolUtils.isPoolReady(pool)) { + throw new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "There is not an available pool for this asset pair" + ); } - const assetOutAmount = BigInt(assetOut.amount); + const [ + {id: assetInID, decimals: assetInDecimals}, + {id: assetOutID, decimals: assetOutDecimals} + ] = [assetIn, assetOut]; + + const assetOutAmount = BigInt(amount); const totalFeeShare = pool.totalFeeShare!; - let assetInID: number; let inputSupply: bigint; let outputSupply: bigint; - if (assetOut.id === pool.asset1ID) { - assetInID = pool.asset2ID; + if (assetOutID === pool.asset1ID) { inputSupply = pool.asset2Reserves!; outputSupply = pool.asset1Reserves!; - } else if (assetOut.id === pool.asset2ID) { - assetInID = pool.asset1ID; + } else if (assetOutID === pool.asset2ID) { inputSupply = pool.asset1Reserves!; outputSupply = pool.asset2Reserves!; } else { - throw new TinymanError( - {pool, assetOut}, - `Output asset (#${ - assetOut.id - }) doesn't belong to the pool ${pool.account.address()}.` + throw new SwapQuoteError( + SwapQuoteErrorType.AssetDoesNotBelongToPoolError, + `Output asset (#${assetOutID}) doesn't belong to the pool ${pool.account.address()}.` ); } @@ -332,26 +407,168 @@ function getFixedOutputSwapQuote({ outputSupply, swapOutputAmount: assetOutAmount, totalFeeShare, - decimals + decimals: { + assetIn: assetInDecimals, + assetOut: assetOutDecimals + } }); if (assetOutAmount > outputSupply) { - throw new OutputAmountExceedsAvailableLiquidityError(); + throw new SwapQuoteError( + SwapQuoteErrorType.OutputAmountExceedsAvailableLiquidityError, + "Output amount exceeds available liquidity." + ); + } + + if (isSwapAssetInAmountLow(Number(swapInputAmount))) { + throw new SwapQuoteError( + SwapQuoteErrorType.LowSwapAmountError, + "Swap amount is too low." + ); } return { - assetInID, - assetInAmount: swapInputAmount, - assetOutID: assetOut.id, - assetOutAmount, - swapFee: Number(totalFeeAmount), - rate: - convertFromBaseUnits(decimals.assetOut, Number(assetOutAmount)) / - convertFromBaseUnits(decimals.assetIn, Number(swapInputAmount)), - priceImpact + type: SwapQuoteType.Direct, + data: { + pool, + quote: { + assetInID, + assetInAmount: swapInputAmount, + assetOutID, + assetOutAmount, + swapFee: Number(totalFeeAmount), + rate: + convertFromBaseUnits(assetOutDecimals, Number(assetOutAmount)) / + convertFromBaseUnits(assetInDecimals, Number(swapInputAmount)), + priceImpact + } + } }; } +/** + * @returns A quote for a fixed input swap. Does NOT execute any transactions. + */ +async function getFixedInputSwapQuote({ + amount, + assetIn, + assetOut, + isSwapRouterEnabled, + network, + pool +}: { + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; + network: SupportedNetwork; + pool: V2PoolInfo | null; + isSwapRouterEnabled?: boolean; +}): Promise { + const quotePromises: Promise[] = []; + + if (pool) { + quotePromises.push( + new Promise((resolve, reject) => { + try { + const quote = getFixedInputDirectSwapQuote({ + amount, + assetIn, + assetOut, + pool + }); + + resolve({ + type: SwapQuoteType.Direct, + data: { + pool, + quote + } + }); + } catch (error) { + reject(error); + } + }) + ); + } else { + quotePromises.push( + Promise.reject( + new SwapQuoteError( + SwapQuoteErrorType.NoAvailablePoolError, + "There is not an available pool for this asset pair" + ) + ) + ); + } + + if (isSwapRouterEnabled) { + quotePromises.push( + getSwapRoute({ + amount, + assetInID: assetIn.id, + assetOutID: assetOut.id, + swapType: SwapType.FixedInput, + network + }).then((data) => ({type: SwapQuoteType.Router, data})) + ); + } + + const validQuotes = await validateQuotes(quotePromises); + + return getBestQuote(validQuotes); +} + +/** + * @returns A quote for a fixed output swap. Does NOT execute any transactions. + */ +async function getFixedOutputSwapQuote({ + amount, + assetIn, + assetOut, + isSwapRouterEnabled, + network, + pool +}: { + amount: number | bigint; + assetIn: AssetWithIdAndDecimals; + assetOut: AssetWithIdAndDecimals; + pool: V2PoolInfo | null; + network: SupportedNetwork; + isSwapRouterEnabled?: boolean; +}): Promise { + const quotePromises: Promise[] = [ + new Promise((resolve, reject) => { + try { + resolve( + getFixedOutputDirectSwapQuote({ + amount, + assetIn, + assetOut, + pool + }) + ); + } catch (error) { + reject(error); + } + }) + ]; + + if (isSwapRouterEnabled) { + quotePromises.push( + getSwapRoute({ + amount, + assetInID: assetIn.id, + assetOutID: assetOut.id, + swapType: SwapType.FixedOutput, + network + }).then((data) => ({type: SwapQuoteType.Router, data})) + ); + } + + const validQuotes = await validateQuotes(quotePromises); + + return getBestQuote(validQuotes); +} + function calculateFixedInputSwap({ inputSupply, outputSupply, @@ -502,6 +719,8 @@ function calculateSwapAmountOfFixedOutputSwap({ export const SwapV2 = { getQuote, getFixedInputSwapQuote, + getFixedInputDirectSwapQuote, + getFixedOutputDirectSwapQuote, getFixedOutputSwapQuote, generateTxns, signTxns, diff --git a/src/swap/v2/router/constants.ts b/src/swap/v2/router/constants.ts new file mode 100644 index 00000000..dee195ac --- /dev/null +++ b/src/swap/v2/router/constants.ts @@ -0,0 +1,15 @@ +import {SupportedNetwork} from "../../../util/commonTypes"; +import {SwapType} from "../../constants"; + +export const SWAP_ROUTER_APP_ID: Record = { + testnet: 184778019, + mainnet: 1083651166 +}; + +/** + * Inner txn counts according to the swap type + */ +export const SWAP_ROUTER_INNER_TXN_COUNT: Record = { + [SwapType.FixedInput]: 7, + [SwapType.FixedOutput]: 8 +} as const; diff --git a/src/swap/v2/router/index.ts b/src/swap/v2/router/index.ts new file mode 100644 index 00000000..05b32ead --- /dev/null +++ b/src/swap/v2/router/index.ts @@ -0,0 +1,2 @@ +export * from "./swap-router"; +export * from "./util"; diff --git a/src/swap/v2/router/swap-router.ts b/src/swap/v2/router/swap-router.ts new file mode 100644 index 00000000..b9a15986 --- /dev/null +++ b/src/swap/v2/router/swap-router.ts @@ -0,0 +1,246 @@ +import algosdk, { + Algodv2, + ALGORAND_MIN_TX_FEE, + getApplicationAddress, + Transaction +} from "algosdk"; + +import {CONTRACT_VERSION} from "../../../contract/constants"; +import {AccountInformation} from "../../../util/account/accountTypes"; +import {ALGO_ASSET_ID} from "../../../util/asset/assetConstants"; +import {getAssetId, isAlgo} from "../../../util/asset/assetUtils"; +import {SupportedNetwork} from "../../../util/commonTypes"; +import SwapQuoteError, {SwapQuoteErrorType} from "../../../util/error/SwapQuoteError"; +import {applySlippageToAmount, hasTinymanApiErrorShape} from "../../../util/util"; +import {getValidatorAppID} from "../../../validator"; +import {SwapType} from "../../constants"; +import {FetchSwapRouteQuotesPayload, SwapRouterResponse, SwapRoute} from "../../types"; +import { + V2_SWAP_APP_CALL_ARG_ENCODED, + V2_SWAP_APP_CALL_SWAP_TYPE_ARGS_ENCODED, + V2_SWAP_ROUTER_APP_ARGS_ENCODED +} from "../constants"; +import {SWAP_ROUTER_INNER_TXN_COUNT} from "./constants"; +import { + getAssetInFromSwapRoute, + getAssetOutFromSwapRoute, + getSwapRouterAppID +} from "./util"; +import {TINYMAN_ANALYTICS_API_BASE_URLS} from "../../../util/constant"; +import {tinymanJSSDKConfig} from "../../../config"; + +/** + * Generates txns that would opt in the Swap Router Application to the assets used in the swap router + */ +export async function generateSwapRouterAssetOptInTransaction({ + client, + routerAppID, + assetIDs, + initiatorAddr +}: { + client: Algodv2; + routerAppID: number; + assetIDs: number[]; + initiatorAddr: string; +}): Promise { + const suggestedParams = await client.getTransactionParams().do(); + // We need to create a NoOp transaction to opt-in to the assets + const assetOptInTxn = algosdk.makeApplicationNoOpTxnFromObject({ + from: initiatorAddr, + appIndex: routerAppID, + appArgs: [V2_SWAP_ROUTER_APP_ARGS_ENCODED.ASSET_OPT_IN], + foreignAssets: assetIDs, + suggestedParams + }); + // The number of inner transactions is the number of assets we're opting in to + const innerTransactionCount = assetIDs.length; + + /** + * The opt-in transaction fee should cover the total cost of inner transactions, + * and the outer transaction (thus the +1) + */ + assetOptInTxn.fee = ALGORAND_MIN_TX_FEE * (innerTransactionCount + 1); + + return assetOptInTxn; +} + +export async function generateSwapRouterTxns({ + initiatorAddr, + client, + network, + swapType, + route, + slippage +}: { + client: Algodv2; + initiatorAddr: string; + swapType: SwapType; + route: SwapRoute; + network: SupportedNetwork; + slippage: number; +}) { + const suggestedParams = await client.getTransactionParams().do(); + + const [assetInID, intermediaryAssetID, assetOutID] = [ + getAssetId(route[0].quote.amount_in.asset), + getAssetId(route[0].quote.amount_out.asset), + getAssetId(route[1].quote.amount_out.asset) + ]; + const [assetInAmountFromRoute, assetOutAmountFromRoute] = [ + Number(getAssetInFromSwapRoute(route).amount), + Number(getAssetOutFromSwapRoute(route).amount) + ]; + const [pool1Address, pool2Address] = [route[0].pool.address, route[1].pool.address]; + + const assetInAmount = + swapType === SwapType.FixedInput + ? assetInAmountFromRoute + : applySlippageToAmount("positive", slippage, assetInAmountFromRoute); + const assetOutAmount = + swapType === SwapType.FixedOutput + ? assetOutAmountFromRoute + : applySlippageToAmount("negative", slippage, assetOutAmountFromRoute); + + const isAssetInAlgo = isAlgo(assetInID); + + const routerAppID = getSwapRouterAppID(network); + + const inputTxn = isAssetInAlgo + ? algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: initiatorAddr, + to: getApplicationAddress(routerAppID), + amount: assetInAmount, + suggestedParams + }) + : algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ + from: initiatorAddr, + to: getApplicationAddress(routerAppID), + amount: assetInAmount, + assetIndex: assetInID, + suggestedParams + }); + + const routerAppCallTxn = algosdk.makeApplicationNoOpTxnFromObject({ + from: initiatorAddr, + appIndex: routerAppID, + appArgs: [ + V2_SWAP_APP_CALL_ARG_ENCODED, + V2_SWAP_APP_CALL_SWAP_TYPE_ARGS_ENCODED[swapType], + algosdk.encodeUint64(assetOutAmount) + ], + foreignApps: [getValidatorAppID(network, CONTRACT_VERSION.V2)], + foreignAssets: [assetInID, intermediaryAssetID, assetOutID], + accounts: [pool1Address, pool2Address], + suggestedParams, + note: tinymanJSSDKConfig.getAppCallTxnNoteWithClientName(CONTRACT_VERSION.V2) + }); + + routerAppCallTxn.fee = + ALGORAND_MIN_TX_FEE * (SWAP_ROUTER_INNER_TXN_COUNT[swapType] + 1); + + const txnList = [inputTxn, routerAppCallTxn]; + + const optInRequiredAssetIDs = await getSwapRouterAppOptInRequiredAssetIDs({ + client, + network, + assetIDs: [assetInID, intermediaryAssetID, assetOutID] + }); + + if (optInRequiredAssetIDs.length > 0) { + const routerAppAssetOptInTxn = await generateSwapRouterAssetOptInTransaction({ + client, + initiatorAddr, + assetIDs: optInRequiredAssetIDs, + routerAppID + }); + + txnList.unshift(routerAppAssetOptInTxn); + } + + const txGroup = algosdk.assignGroupID(txnList); + + return txGroup.map((txn: Transaction) => ({ + txn, + signers: [initiatorAddr] + })); +} + +export async function getSwapRouterAppOptInRequiredAssetIDs({ + client, + network, + assetIDs +}: { + client: Algodv2; + network: SupportedNetwork; + assetIDs: number[]; +}) { + const swapRouterAppAddress = getApplicationAddress(getSwapRouterAppID(network)); + const accountInfo = (await client + .accountInformation(swapRouterAppAddress) + .do()) as AccountInformation; + const appOptedInAssetIDs = accountInfo.assets.map((asset) => asset["asset-id"]); + + return assetIDs.filter( + (assetID: number) => + assetID !== ALGO_ASSET_ID && !appOptedInAssetIDs.includes(assetID) + ); +} + +export async function getSwapRoute({ + amount, + assetInID, + assetOutID, + swapType, + network +}: { + assetInID: number; + assetOutID: number; + swapType: SwapType; + amount: number | bigint; + network: SupportedNetwork; +}): Promise { + const payload: FetchSwapRouteQuotesPayload = { + asset_in_id: String(assetInID), + asset_out_id: String(assetOutID), + swap_type: swapType, + amount: String(amount) + }; + + const response = await fetch( + `${TINYMAN_ANALYTICS_API_BASE_URLS[network].v1}/swap-router/quotes/`, + { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(payload) + } + ).catch(() => { + throw new Error("Network error"); + }); + + const serializedResponse = await response.json(); + + if (!response.ok) { + if (hasTinymanApiErrorShape(serializedResponse)) { + throw new SwapQuoteError( + serializedResponse.type as SwapQuoteErrorType, + serializedResponse.fallback_message + ); + } else { + throw new SwapQuoteError( + SwapQuoteErrorType.UnknownError, + "There was an error while getting a quote from Swap Router" + ); + } + } + + if ((serializedResponse as SwapRouterResponse).route.length < 2) { + throw new SwapQuoteError( + SwapQuoteErrorType.SwapRouterNoRouteError, + "Swap router couldn't find a route for this swap." + ); + } + + return serializedResponse; +} diff --git a/src/swap/v2/router/util.ts b/src/swap/v2/router/util.ts new file mode 100644 index 00000000..a8c10b10 --- /dev/null +++ b/src/swap/v2/router/util.ts @@ -0,0 +1,46 @@ +import {SupportedNetwork} from "../../../util/commonTypes"; +import {convertFromBaseUnits} from "../../../util/util"; +import {SwapRoute} from "../../types"; +import {SWAP_ROUTER_APP_ID} from "./constants"; + +function getSwapRouteRate(route: SwapRoute) { + const {assetIn, assetOut} = getAssetInAndOutFromSwapRoute(route); + + return ( + convertFromBaseUnits(assetOut.asset.decimals, Number(assetOut.amount)) / + convertFromBaseUnits(assetIn.asset.decimals, Number(assetIn.amount)) + ); +} + +function getSwapRouterAppID(network: SupportedNetwork) { + const id = SWAP_ROUTER_APP_ID[network]; + + if (!id) { + throw new Error(`Unknown network or network not supported: ${network}`); + } + + return id; +} + +function getAssetOutFromSwapRoute(route: SwapRoute) { + return route[route.length - 1].quote.amount_out; +} + +function getAssetInFromSwapRoute(route: SwapRoute) { + return route[0].quote.amount_in; +} + +function getAssetInAndOutFromSwapRoute(route: SwapRoute) { + return { + assetIn: getAssetInFromSwapRoute(route), + assetOut: getAssetOutFromSwapRoute(route) + }; +} + +export { + getSwapRouteRate, + getSwapRouterAppID, + getAssetOutFromSwapRoute, + getAssetInFromSwapRoute, + getAssetInAndOutFromSwapRoute +}; diff --git a/src/swap/v2/util.ts b/src/swap/v2/util.ts index 59c87d81..1c462d22 100644 --- a/src/swap/v2/util.ts +++ b/src/swap/v2/util.ts @@ -1,6 +1,6 @@ import {ALGORAND_MIN_TX_FEE} from "algosdk"; -import {SwapType} from "../constants"; +import {SwapType, DEFAULT_SWAP_FEE_RATE} from "../constants"; import {V2_SWAP_APP_CALL_INNER_TXN_COUNT, V2_SWAP_TXN_COUNT} from "./constants"; /** @@ -11,3 +11,27 @@ export function getV2SwapTotalFee(mode: SwapType) { return totalTxnCount * ALGORAND_MIN_TX_FEE; } + +/** + * @returns the minimum possible amount of assetIn that can be used for swap in V2 pools + */ +export function getV2MinSwapAssetInAmount(feeRate: number = DEFAULT_SWAP_FEE_RATE) { + return Math.ceil(1 / feeRate); +} + +/** + * @returns true if the amount of assetIn is less than the minimum possible amount of assetIn that can be used for swap in V2 pools + */ +export function isSwapAssetInAmountLow( + amount: number, + feeRate: number = DEFAULT_SWAP_FEE_RATE +) { + return amount < getV2MinSwapAssetInAmount(feeRate); +} + +export function getSwapAppCallFeeAmount(swapType: SwapType) { + // Add +1 to account for the outer txn fee + const totalTxnCount = V2_SWAP_APP_CALL_INNER_TXN_COUNT[swapType] + 1; + + return totalTxnCount * ALGORAND_MIN_TX_FEE; +} diff --git a/src/util/asset/assetModels.ts b/src/util/asset/assetModels.ts index 4eebcde1..00bfac52 100644 --- a/src/util/asset/assetModels.ts +++ b/src/util/asset/assetModels.ts @@ -55,6 +55,11 @@ export interface AssetWithIdAndAmount { amount: number | bigint; } +export interface AssetWithIdAndDecimals { + id: number; + decimals: number; +} + export interface AssetWithAmountAndDecimals { amount: number | bigint; decimals: number; diff --git a/src/util/asset/assetUtils.ts b/src/util/asset/assetUtils.ts index 00c18283..3362cd8a 100644 --- a/src/util/asset/assetUtils.ts +++ b/src/util/asset/assetUtils.ts @@ -73,3 +73,10 @@ export function sortAssetIds(asset1ID: number, asset2ID: number): number[] { export function isAlgo(id: number | string) { return Number(id) === ALGO_ASSET_ID; } + +/** + * @returns Asset id as a number + */ +export function getAssetId(asset: {id: string | number}): number { + return Number(asset.id); +} diff --git a/src/util/commonTypes.ts b/src/util/commonTypes.ts index fe69949d..f08670eb 100644 --- a/src/util/commonTypes.ts +++ b/src/util/commonTypes.ts @@ -16,6 +16,15 @@ export type InitiatorSigner = ( export type SupportedNetwork = "testnet" | "mainnet"; +export interface TinymanApiErrorDetailShape { + [x: string]: undefined | any; +} + +export interface TinymanApiErrorShape { + type: Type; + detail: TinymanApiErrorDetailShape; + fallback_message: string; +} /** * Type of the waitForConfirmation()["inner-txns"] * NOT a complete type, only the fields we need. @@ -27,10 +36,12 @@ export type TxnResponseInnerTxns = { type: TransactionType.axfer; xaid: number; aamt: number; + arcv: Uint8Array; } | { type: TransactionType.pay; amt: number; + rcv: Uint8Array; } | { /** diff --git a/src/util/constant.ts b/src/util/constant.ts index ced87930..ad88cc23 100644 --- a/src/util/constant.ts +++ b/src/util/constant.ts @@ -1,3 +1,5 @@ +import {SupportedNetwork} from "./commonTypes"; + export const MAX_SLIPPAGE_FRACTION_DIGITS = 6; // The fee paying transaction at group index 0 should have a note value set to distinguish it from other Pay transactions in the group which might have the exact same value. @@ -14,3 +16,17 @@ export const MINIMUM_BALANCE_REQUIRED_PER_INT_SCHEMA_VALUE = 28_500; export const MINIMUM_ADD_LIQUIDITY_AMOUNT = 1000; export const DEFAULT_WAIT_FOR_CONFIRMATION_ROUNDS = 1000; + +export const TINYMAN_ANALYTICS_API_BASE_URLS: Record< + SupportedNetwork, + {base: string; v1: string} +> = { + mainnet: { + base: "https://mainnet.analytics.tinyman.org/api", + v1: "https://mainnet.analytics.tinyman.org/api/v1" + }, + testnet: { + base: "https://testnet.analytics.tinyman.org/api", + v1: "https://testnet.analytics.tinyman.org/api/v1" + } +}; diff --git a/src/util/error/OutputAmountExceedsAvailableLiquidityError.ts b/src/util/error/OutputAmountExceedsAvailableLiquidityError.ts deleted file mode 100644 index a04aefe3..00000000 --- a/src/util/error/OutputAmountExceedsAvailableLiquidityError.ts +++ /dev/null @@ -1,7 +0,0 @@ -class OutputAmountExceedsAvailableLiquidityError extends Error { - constructor(message = "Output amount exceeds available liquidity") { - super(message); - } -} - -export default OutputAmountExceedsAvailableLiquidityError; diff --git a/src/util/error/SwapQuoteError.ts b/src/util/error/SwapQuoteError.ts new file mode 100644 index 00000000..c6883a1f --- /dev/null +++ b/src/util/error/SwapQuoteError.ts @@ -0,0 +1,31 @@ +export enum SwapQuoteErrorType { + SwapRouterStaleDataError = "SwapRouterStaleDataError", + SwapRouterNoRouteError = "SwapRouterNoRouteError", + SwapRouterLowSwapAmountError = "SwapRouterLowSwapAmountError", + SwapRouterInsufficientReservesError = "SwapRouterInsufficientReservesError", + SwapRouterPoolHasNoLiquidityError = "SwapRouterPoolHasNoLiquidityError", + NoAvailablePoolError = "NoAvailablePoolError", + OutputAmountExceedsAvailableLiquidityError = "OutputAmountExceedsAvailableLiquidityError", + UnknownError = "UnknownError", + LowSwapAmountError = "LowSwapAmountError", + AssetDoesNotBelongToPoolError = "AssetDoesNotBelongToPoolError", + InvalidSwapTypeError = "InvalidSwapTypeError" +} + +class SwapQuoteError extends Error { + type: SwapQuoteErrorType; + message: string; + + constructor(type: SwapQuoteErrorType, message: string) { + super(message); + + this.type = type; + this.message = message; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, SwapQuoteError); + } + } +} + +export default SwapQuoteError; diff --git a/src/util/transaction/transactionUtils.ts b/src/util/transaction/transactionUtils.ts index d3fa6e46..bc660620 100644 --- a/src/util/transaction/transactionUtils.ts +++ b/src/util/transaction/transactionUtils.ts @@ -1,8 +1,9 @@ -import { +import algosdk, { Algodv2, assignGroupID, decodeUnsignedTransaction, encodeUnsignedTransaction, + Transaction, TransactionType, waitForConfirmation } from "algosdk"; @@ -51,17 +52,26 @@ export async function getAppCallInnerAssetData( txGroup: SignerTransaction[] ): Promise { const innerTxns = await getAppCallInnerTxns(client, txGroup); + // Get the account address that will receive the assets after a certain operation is successful. + // This equals to the address of the account that signs the txGroup. + const receivingAccountAddress = extractSenderAddressFromTransaction(txGroup[0].txn); return innerTxns?.reduce((assets, {txn}) => { let updatedAssets = assets; const {txn: innerTxn} = txn; - if (innerTxn.type === TransactionType.axfer) { + if ( + innerTxn.type === TransactionType.axfer && + algosdk.encodeAddress(innerTxn.arcv) === receivingAccountAddress + ) { updatedAssets.push({ id: innerTxn.xaid, amount: innerTxn.aamt }); - } else if (innerTxn.type === TransactionType.pay) { + } else if ( + innerTxn.type === TransactionType.pay && + algosdk.encodeAddress(innerTxn.rcv) === receivingAccountAddress + ) { updatedAssets.push({ // Payment transactions are always in ALGO id: ALGO_ASSET_ID, @@ -104,3 +114,12 @@ export function combineAndRegroupSignerTxns( txn: newTxnGroup[index] })); } + +/** + * Extracts the account address from the provided transaction. + * @param txn - The transaction to extract the sender address from + * @returns the account address of the sender + */ +export function extractSenderAddressFromTransaction(txn: Transaction): string { + return algosdk.encodeAddress(txn.from.publicKey); +} diff --git a/src/util/util.ts b/src/util/util.ts index 65c4c0a2..9f4837b0 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,6 +1,6 @@ import {Algodv2} from "algosdk"; -import {SignerTransaction} from "./commonTypes"; +import {SignerTransaction, TinymanApiErrorShape} from "./commonTypes"; import {AccountInformation} from "./account/accountTypes"; import TinymanError from "./error/TinymanError"; @@ -331,3 +331,7 @@ export function encodeInteger(number) { export function encodeString(text: string) { return new TextEncoder().encode(text); } + +export function hasTinymanApiErrorShape(error: any): error is TinymanApiErrorShape { + return Boolean(error) && typeof error.fallback_message !== "undefined"; +}