@minswap/noodles-sdk 0.0.38-next.0 → 0.0.38-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3317 -1
- package/dist/index.js +3152 -1
- package/dist/pay.cjs +905 -1
- package/dist/pay.js +829 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1 +1,3152 @@
|
|
|
1
|
-
import{BluefinXTx as e,Config as t,buildTx as n,getQuote as i}from"@7kprotocol/sdk-ts";import{Transaction as r}from"@mysten/sui/transactions";import o from"bignumber.js";import{Aftermath as a,Helpers as s}from"aftermath-ts-sdk";import{buildSwapPTBFromQuote as u,getCoins as l,getQuote as c}from"@naviprotocol/astros-aggregator-sdk";import{AggregatorClient as d,Env as g}from"@cetusprotocol/aggregator-sdk";import p from"bn.js";import{AggregatorQuoter as f,Coin as m,Commission as A,CommissionType as h,TradeBuilder as _}from"@flowx-finance/sdk";import I from"@minswap/tiny-invariant";import{fromBase64 as C,normalizeStructTag as b}from"@mysten/sui/utils";import{MemezPumpSDK as y}from"@interest-protocol/memez-fun-sdk";import{Network as T}from"@interest-protocol/sui-core-sdk";import{SuiClient as w,getFullnodeUrl as B}from"@mysten/sui/client";import{Ed25519Keypair as v}from"@mysten/sui/keypairs/ed25519";class F{_config;_suiClient;constructor(e,t){this._config=e,this._suiClient=t}async getTradeRoute({coinInAmount:e,coinInType:n,coinOutType:r,tradeFee:o}){try{this._config.sevenKApiKey&&t.setApiKey(this._config.sevenKApiKey);let a=o?o.tradeFeePercent:this._config.defaultTradeFee.tradeFeePercent;return await i({tokenIn:n,tokenOut:r,amountIn:e.toString(),commissionBps:1e4*a})}catch(e){return null}}async getTransaction({walletAddress:t,completeRoute:i,slippage:o,tradeFee:a}){let s,u;a?(s=a.tradeFeePercent,u=a.tradeFeeRecipientAddress):(s=this._config.defaultTradeFee.tradeFeePercent,u=this._config.defaultTradeFee.tradeFeeRecipientAddress);let l=await n({quoteResponse:i,slippage:o,accountAddress:t,commission:{partner:u,commissionBps:1e4*s}});return l.tx instanceof e?r.from(l.tx.txBytes).build({client:this._suiClient}):(l.tx.setSender(t),l.tx.build({client:this._suiClient}))}}(F||(F={})).toCommonTradeRoutes=function(e){let t=[];if(!e.routes||0===e.routes.length)return null;for(let n of e.routes){let e=[],i={};for(let t of n.hops){for(let e of t.pool.allTokens)i[e.address]=e.decimal;let n=i[t.tokenIn]??0,r=i[t.tokenOut]??0,a=BigInt(new o(t.tokenInAmount).multipliedBy(10**n).toFixed(0,3)),s=BigInt(new o(t.tokenOutAmount).multipliedBy(10**r).toFixed(0,3));e.push({poolAddress:t.poolId,coinIn:t.tokenIn,coinOut:t.tokenOut,amountIn:a,amountOut:s})}if(0===e.length)continue;let r=i[n.tokenIn]??0,a=i[n.tokenOut]??0,s=BigInt(new o(n.tokenInAmount).multipliedBy(10**r).toFixed(0,3)),u=BigInt(new o(n.tokenOutAmount).multipliedBy(10**a).toFixed(0,3));t.push({paths:e,coinIn:n.tokenIn,coinOut:n.tokenOut,amountIn:s,amountOut:u})}return 0===t.length?null:{coinIn:e.tokenIn,coinOut:e.tokenOut,amountIn:BigInt(e.swapAmountWithDecimal),amountOut:BigInt(e.returnAmountWithDecimal),routes:t}};class O{_config;_aftermathClient;_suiClient;constructor(e,t){this._config=e,this._suiClient=t}async aftermathClient(){if(this._aftermathClient)return this._aftermathClient;if(this._config.aftermathApiEndpoint?this._aftermathClient=new a(this._config.aftermathApiEndpoint):this._aftermathClient=new a("MAINNET"),await this._aftermathClient.init(),this._config.aftermathApiKey){let e=s.keypairFromPrivateKey(this._config.aftermathApiKey);await this._aftermathClient.Auth().init({async signMessageCallback({message:t}){let{signature:n}=await e.signPersonalMessage(t);return{signature:n}},walletAddress:e.toSuiAddress()})}return this._aftermathClient}async getTradeRoute({coinInAmount:e,coinInType:t,coinOutType:n,tradeFee:i}){try{let r;r=i?{recipient:i.tradeFeeRecipientAddress,feePercentage:i.tradeFeePercent}:{recipient:this._config.defaultTradeFee.tradeFeeRecipientAddress,feePercentage:this._config.defaultTradeFee.tradeFeePercent};let o=await this.aftermathClient();return await o.Router().getCompleteTradeRouteGivenAmountIn({coinInAmount:e,coinInType:t,coinOutType:n,externalFee:r})}catch(e){return null}}async getTransaction({completeRoute:e,walletAddress:t,slippage:n}){let i=await this.aftermathClient(),r=await i.Router().getTransactionForCompleteTradeRoute({completeRoute:e,walletAddress:t,slippage:n,isSponsoredTx:!1});return r.setSender(t),r.build({client:this._suiClient})}}(O||(O={})).toCommonTradeRoutes=function(e){if(0===e.routes.length)return null;let t=[];for(let n of e.routes){let e=[];for(let t of n.paths)e.push({poolAddress:t.poolId,coinIn:t.coinIn.type,coinOut:t.coinOut.type,amountIn:BigInt(t.coinIn.amount),amountOut:BigInt(t.coinOut.amount)});0!==e.length&&t.push({paths:e,coinIn:n.coinIn.type,coinOut:n.coinOut.type,amountIn:n.coinIn.amount,amountOut:n.coinOut.amount})}return 0===t.length?null:{coinIn:e.coinIn.type,coinOut:e.coinOut.type,amountIn:e.coinIn.amount,amountOut:e.coinOut.amount,routes:t}};class S{_config;_suiClient;constructor(e,t){this._config=e,this._suiClient=t}async getTradeRoute({coinInAmount:e,coinInType:t,coinOutType:n,tradeFee:i}){try{let r;return r=i?{fee:i.tradeFeePercent,receiverAddress:i.tradeFeeRecipientAddress}:{fee:this._config.defaultTradeFee.tradeFeePercent,receiverAddress:this._config.defaultTradeFee.tradeFeeRecipientAddress},await c(t,n,e,this._config.astrosApiKey,{byAmountIn:!0,serviceFee:r})}catch(e){return null}}returnMergedCoins(e,t,n){if(t.length<2)return e.object(t[0].coinObjectId);let i=0,r=[];t.sort((e,t)=>Number(t.balance)-Number(e.balance)).slice(1).forEach(e=>{i>=n||(i+=Number(e.balance),r.push(e.coinObjectId))});let o=t[0].coinObjectId;return e.mergeCoins(o,r),e.object(o)}async getTransaction({completeRoute:e,walletAddress:t,slippage:n,tradeFee:i}){var a;let s,c;s=i?{fee:i.tradeFeePercent,receiverAddress:i.tradeFeeRecipientAddress}:{fee:this._config.defaultTradeFee.tradeFeePercent,receiverAddress:this._config.defaultTradeFee.tradeFeeRecipientAddress};let d=new o(e.amount_out).multipliedBy(1-n-s.fee).toNumber(),g=new r;if("0x2::sui::SUI"===(a=e.from)||"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"===a)c=g.splitCoins(g.gas,[g.pure.u64(e.amount_in)]);else{let n=await l(this._suiClient,t,e.from),i=this.returnMergedCoins(g,n.data,Number.parseFloat(e.amount_in));c=g.splitCoins(i,[g.pure.u64(e.amount_in)])}let p=await u(t,g,d,c,e,void 0,!1,this._config.astrosApiKey,{serviceFee:s});return g.transferObjects([p],t),g.setSender(t),g.build({client:this._suiClient})}}(S||(S={})).toCommonTradeRoutes=function(e,t,n){if(0===e.routes.length)return null;let i=[];for(let t of e.routes){let e=[];for(let n of t.path)e.push({poolAddress:n.id,coinIn:n.from,coinOut:n.target,amountIn:BigInt(n.amount_in),amountOut:BigInt(n.amount_out)});0!==e.length&&i.push({amountIn:BigInt(t.amount_in),amountOut:BigInt(t.amount_out),coinIn:e[0].coinIn,coinOut:e[e.length-1].coinOut,paths:e})}return 0===i.length?null:{coinIn:t,coinOut:n,amountIn:BigInt(e.amount_in),amountOut:BigInt(e.amount_out),routes:i}},(z||(z={})).equals=function(e,t){return e.tradeFeePercent===t.tradeFeePercent&&e.tradeFeeRecipientAddress===t.tradeFeeRecipientAddress};class x{_config;_suiClient;_cetusClient;constructor(e,t){this._config=e,this._suiClient=t}cetusClient(e,t){return t&&!z.equals(t,this._config.defaultTradeFee)?new d({client:this._suiClient,overlayFeeReceiver:t.tradeFeeRecipientAddress,overlayFeeRate:t.tradeFeePercent,env:g.Mainnet,signer:e,...this._config.cetusApiKey&&this._config.cetusApiEndpoint?{apiKey:this._config.cetusApiKey,endpoint:this._config.cetusApiEndpoint}:{},partner:this._config.cetusPartnerId}):(this._cetusClient||(this._cetusClient=new d({client:this._suiClient,overlayFeeReceiver:this._config.defaultTradeFee.tradeFeeRecipientAddress,overlayFeeRate:this._config.defaultTradeFee.tradeFeePercent,env:g.Mainnet,signer:e,...this._config.cetusApiKey&&this._config.cetusApiEndpoint?{apiKey:this._config.cetusApiKey,endpoint:this._config.cetusApiEndpoint}:{},partner:this._config.cetusPartnerId})),this._cetusClient)}async getTradeRoute({coinInAmount:e,coinInType:t,coinOutType:n,tradeFee:i}){try{let r=this.cetusClient(void 0,i);return await r.findRouters({from:t,target:n,amount:new p(e.toString()),byAmountIn:!0})}catch(e){return null}}async getTransaction({completeRoute:e,walletAddress:t,slippage:n,tradeFee:i}){let o=this.cetusClient(t,i),a=new r;return a.setSender(t),await o.fastRouterSwap({router:e,txb:a,slippage:n}),await o.devInspectTransactionBlock(a),a.build({client:this._suiClient})}}(x||(x={})).toCommonTradeRoutes=function(e,t,n){if(0===e.paths.length)return null;let i=[],r=[],o=[];for(let t=0;t<e.paths.length;t++){let n=e.paths[t],i={poolAddress:n.id,amountIn:BigInt(n.amountIn),amountOut:BigInt(n.amountOut),coinIn:n.from,coinOut:n.target};if(o.push(i),t===e.paths.length-1)r.push([...o]);else{let i=e.paths[t+1];n.target!==i.from&&(r.push([...o]),o=[])}}for(let e of r)0!==e.length&&i.push({amountIn:e[0].amountIn,amountOut:e[e.length-1].amountOut,coinIn:e[0].coinIn,coinOut:e[e.length-1].coinOut,paths:e});return 0===i.length?null:{coinIn:t,coinOut:n,amountIn:BigInt(e.amountIn.toString(10)),amountOut:BigInt(e.amountOut.toString(10)),routes:i}};var k,R,E,P,M,j,D,N,U,K,G,q,$,L,z,W,J,V,X,Y,Z,H,Q,ee,et,en,ei,er,eo=((L={}).ASTROS="ASTROS",L.AFTERMATH="AFTERMATH",L.SEVENK="7K",L.CETUS="CETUS",L.FLOWX="FLOWX",L);class ea{_config;_suiClient;constructor(e,t){this._config=e,this._suiClient=t}getCommission(e,t){let n,i;return t?(n=t.tradeFeePercent,i=t.tradeFeeRecipientAddress):(n=this._config.defaultTradeFee.tradeFeePercent,i=this._config.defaultTradeFee.tradeFeeRecipientAddress),new A(i,new m(e),h.PERCENTAGE,1e6*n,!0)}async getTradeRoute({coinInAmount:e,coinInType:t,coinOutType:n,tradeFee:i}){let r=new f("mainnet",this._config.flowxApiKey);try{return await r.getRoutes({tokenIn:t,tokenOut:n,amountIn:e.toString(),commission:this.getCommission(t,i)})}catch(e){return null}}async getTransaction({walletAddress:e,completeRoute:t,slippage:n,tradeFee:i}){return new _("mainnet",t.routes).sender(e).slippage(1e6*n).commission(this.getCommission(t.coinIn.coinType,i)).build().buildTransaction({client:this._suiClient}).then(t=>(t.setSender(e),t.build({client:this._suiClient})))}}async function es(e,t){return(await eu(e,t)).fields}async function eu(e,t){let n=await e.getObject({id:t,options:{showContent:!0}}),i=n.data?.content;return I(i,"Pool object not found or has no content"),I("moveObject"===i.dataType,"Object is not a Move object"),i}function el(e,t){let n=BigInt(e),i=BigInt(1e4*Number(t));if(i===BigInt(0))return[n.toString()];let r=n*i/BigInt(1e4);return[(n-r).toString(),r.toString()]}function ec(e,t){if(!t||0>=Number(t))return BigInt(e);let n=BigInt(e),i=BigInt(1e4*Number(t));if(i===BigInt(0))return n;let r=n*i/BigInt(1e4);return n-r}async function ed(e,t,n,i){let{effects:{gasUsed:r,status:o}}=await e.devInspectTransactionBlock({sender:n,transactionBlock:t});if("success"!==o.status)throw Error(`Transaction failed during dev inspect: ${o.error??""}`);let a=BigInt(r.computationCost)+BigInt(r.storageCost)-BigInt(r.storageRebate),s=BigInt(1e4*Number(i));return a*(BigInt(1e4)+s)/BigInt(1e4)}(ea||(ea={})).toCommonTradeRoutes=function(e){if(0===e.routes.length)return null;let t=[];for(let n of e.routes){let e=[];for(let t of n.paths)e.push({amountIn:BigInt(t.amountIn.toString()),amountOut:BigInt(t.amountOut.toString()),coinIn:t.input.coinType,coinOut:t.output.coinType,poolAddress:t.pool.id});0!==e.length&&t.push({amountIn:BigInt(n.amountIn.toString()),amountOut:BigInt(n.amountOut.toString()),coinIn:n.input.coinType,coinOut:n.output.coinType,paths:e})}return 0===t.length?null:{coinIn:e.coinIn.coinType,coinOut:e.coinOut.coinType,amountIn:BigInt(e.amountIn.toString()),amountOut:BigInt(e.amountOut.toString()),routes:t}},(k=W||(W={})).PACKAGE_ID_V4="0x7e6aa6e179466ab2814425a780b122575296d011119fa69d27f289f5a28814bd",k.MEMEZ_AV_OBJECT_ID="0x2319e3e76dfad73d8f4684bdbf42be4f32d8ce4521dd61becc8261dc918d82c0",((R=J||(J={})).U64||(R.U64={})).mulDivUp=function(e,t,n){let i=BigInt(0);return e*t%n>BigInt(0)&&(i=BigInt(1)),e*t/n+i};var eg=V||(V={});function ep(e){return I(BigInt(e)<=BigInt(1e4),"Bps overflow"),BigInt(e)}eg.calcUp=function(e,t){let n,i=BigInt(e.pos0),r=BigInt(1e4);return n=i*t%r!==BigInt(0)?BigInt(1):BigInt(0),i*t/r+n},eg.sub=function(e,t){return I(BigInt(e.pos0)>=BigInt(t.pos0),"Bps underflow"),{pos0:(BigInt(e.pos0)-BigInt(t.pos0)).toString()}},eg.value=function(e){return BigInt(e.pos0)},eg.new_=function(e){return{pos0:ep(e).toString()}},eg.assertOverflow=ep,((E=X||(X={})).MemezFun||(E.MemezFun={})).isSniperProtectedMemezFun=async function(e,t){return(await es(e,t)).public_key.length>0},(P=E.MemezFees||(E.MemezFees={})).takeWithDiscount=function(e,t,n){if("Value"===e.variant){let n=BigInt(e.fields.pos0);if(n===BigInt(0))return BigInt(0);if(t>=n)return n;throw Error(`Insufficient amount to cover fee. Required: ${n}, provided: ${t}`)}if("Percentage"===e.variant){let i=e.fields.pos0.fields;if(BigInt(i.pos0)===BigInt(0))return BigInt(0);let r=V.calcUp(V.sub(i,n),t);if(t>=r)return r;throw Error(`Insufficient amount to cover fee. Required: ${r}, provided: ${t}`)}throw Error("Unknown fee variant")},P.calculateWithDiscount=function(e,t,n){if("Value"===e.variant)return BigInt(e.fields.pos0);if("Percentage"===e.variant){let i=e.fields.pos0.fields;return V.calcUp(V.sub(i,t),n)}throw Error("Unknown fee variant")},(E.MemezBurner||(E.MemezBurner={})).calculate=function(e,t){if(V.value(e.fee.fields)===BigInt(0)||t===BigInt(0)||t>=BigInt(e.target_liquidity))return V.new_(0);let n=BigInt(1e4);return V.new_(J.U64.mulDivUp(V.value(e.fee.fields),J.U64.mulDivUp(t,n,BigInt(e.target_liquidity)),n))},(M=E.MemezPump||(E.MemezPump={})).getPumpState=async function(e,t){return await es(e,t.inner_state)},M.pump=function(e,t){let n=e.constant_product.fields,i=E.MemezFees.takeWithDiscount(n.quote_swap_fee,t,n.quote_referrer_fee.fields),r=t-i,o=BigInt(n.meme_balance),a=BigInt(n.quote_balance),s=o*r/(BigInt(n.virtual_liquidity)+a+r),u=E.MemezFees.takeWithDiscount(n.meme_swap_fee,s,n.meme_referrer_fee.fields);return s-u},M.dump=function(e,t){let n=e.constant_product.fields,i=E.MemezFees.takeWithDiscount(n.meme_swap_fee,t,n.meme_referrer_fee.fields),r=t-i,o=BigInt(n.meme_balance),a=BigInt(n.quote_balance),s=BigInt(n.virtual_liquidity),u=E.MemezBurner.calculate(n.burner.fields,a),l=V.calcUp(u,r),c=r-(V.value(u)!==BigInt(0)?l:BigInt(0)),d=(s+a)*c/(o+c);d>a&&(d=a);let g=E.MemezFees.takeWithDiscount(n.quote_swap_fee,d,n.quote_referrer_fee.fields);return d-g},(j=Y||(Y={})).getCurveAmountAfterBuy=async function(e,t){let{suiAmount:n,poolId:i,frontendFee:r}=e,o=await es(t,i),a=await X.MemezPump.getPumpState(t,o);return n=ec(n,r),X.MemezPump.pump(a,n)},j.getSuiAmountAfterSell=async function(e,t){let{curveAmount:n,poolId:i,frontendFee:r}=e,o=await es(t,i),a=await X.MemezPump.getPumpState(t,o);return ec(X.MemezPump.dump(a,n),r)};let ef="0x2::sui::SUI",em="0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",eA="0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",eh="0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",e_="0x9258181f5ceac8dbffb7030890243caed69a9599d2886d957a9cb7656af3bdb3",eI="0x0000000000000000000000000000000000000000000000000000000000000006";function eC(e){return e===ef||e===em}let eb=async(e,t,n,i)=>{let r,o=[],a=!0;for(;a;)try{let n=await e.getCoins({owner:t,coinType:i,cursor:r});o=[...o,...n.data],a=n.hasNextPage,r=n.nextCursor}catch(e){console.error("Error fetching data:",e),a=!1}let s=((e,t,n)=>{let i;if(e?.length){do{i=!1;for(let r=0;r<e.length-1;r++){let o=BigInt(e[r][t]),a=BigInt(e[r+1][t]);if("desc"===n?o<a:o>a){let t=e[r];e[r]=e[r+1],e[r+1]=t,i=!0}}}while(i);return e}})(o.map(e=>({...e,balance:e.balance})),"balance","desc")??[],u="0",l=[],c=[];for(let e of s)if(u=(BigInt(e.balance)+BigInt(u)).toString(10),l.push(e.coinObjectId),c.push(e),BigInt(u)>=BigInt(n))break;return{objectIds:l,balance:u,objectCoins:c}};async function ey(e,t){let{account:n,amount:i,splits:o,coinType:a,inheritTx:s,inspecTransaction:u,isSponsored:l=!1}=e,c=s??new r,{objectIds:d}=await eb(t,n,i,a),g=d[0];if(b(a)===b(em)&&!l){let e;return u?(d.length>1&&c.mergeCoins(c.object(g),d.slice(1).map(e=>c.object(e))),e=c.splitCoins(c.object(g),o)):e=c.splitCoins(c.gas,o),{tx:c,coinData:e}}d.length>1&&c.mergeCoins(c.object(g),d.slice(1).map(e=>c.object(e)));let p=c.splitCoins(c.object(g),o);return{tx:c,coinData:p}}let eT="0x62412b7268c35f3808336aee57a52836501f40b8ba5d936f8ad275e672befd04";async function ew(e,t){let n,i,{inputAmount:o,accountAddress:a,frontendFee:s,frontendFeeRecipient:u,extendTx:l,isSponsored:c}=e;I(e.inCoinType===em||e.inCoinType===ef,"Input must be SUI");let{tx:d,coinIn:g}=l||{},p=el(o,s||"0"),f=d||new r;if(g)n=f.splitCoins(g,p),Z.transferOrDestroyZeroCoin(f,em,g,a);else{let{coinData:e}=await ey({account:a,amount:o,splits:p,coinType:em,inheritTx:f,isSponsored:c||!1},t);n=e}if(s&&u){let[e,t]=n;i=e,f.transferObjects([t],f.pure.address(u||a))}else[i]=n;return{tx:f,coinOut:i}}async function eB(e,t,n){if(I(t.outCoinType===em||t.outCoinType===ef,"Output must be SUI"),0>=Number(t.frontendFee||0))return{tx:e,coinOut:n};let i=e.moveCall({target:"0x2::coin::value",typeArguments:[t.outCoinType],arguments:[n]}),r=e.moveCall({target:`${eT}::math::mul_div_u64`,typeArguments:[],arguments:[i,e.pure.u64(BigInt(1e4*Number(t.frontendFee||"0"))),e.pure.u64(BigInt(1e4))]}),o=e.moveCall({target:"0x2::coin::split",typeArguments:[t.outCoinType],arguments:[n,r]});return e.transferObjects([o],e.pure.address(t.frontendFeeRecipient||t.accountAddress)),{tx:e,coinOut:n}}(Z||(Z={})).transferOrDestroyZeroCoin=function(e,t,n,i){e.moveCall({target:`${eT}::utils::transfer_or_destroy`,typeArguments:[t],arguments:[n,e.pure.address(i)]})};var ev=H||(H={});async function eF(e){let t=e||new r;return t.moveCall({target:`${W.PACKAGE_ID_V4}::memez_allowed_versions::get_allowed_versions`,arguments:[t.object(W.MEMEZ_AV_OBJECT_ID)],typeArguments:[]})}ev.getAllowedVersions=eF,ev.buildBuyTx=async function(e,t){I(!await X.MemezFun.isSniperProtectedMemezFun(t,e.poolId),"This coin is a sniper protected coin, please use the Blast Fun website to trade it.");let{tx:n,coinOut:i}=await ew(e,t);I(i,"Coin out is required");let r=n.moveCall({target:`${W.PACKAGE_ID_V4}::memez_pump::pump`,typeArguments:[e.outCoinType,em],arguments:[n.object(e.poolId),i,n.pure.vector("address",[]),n.pure.vector("vector<u8>",[]),n.pure.u64(e.minAmountOut),await eF(n)]});return{tx:n,coinOut:r}},ev.buildSellTx=async function(e,t){I(e.outCoinType===em||e.outCoinType===ef,"Output must be SUI");let n=await es(t,e.poolId),{tx:i,coinData:r}=await ey({amount:e.inputAmount,coinType:e.inCoinType,inheritTx:e.extendTx?.tx,account:e.accountAddress,splits:[e.inputAmount]},t),[o]=r,[a]=i.moveCall({target:`${W.PACKAGE_ID_V4}::memez_pump::dump`,typeArguments:[e.inCoinType,e.outCoinType],arguments:[i.object(e.poolId),i.object(n.ipx_meme_coin_treasury),o,i.pure.vector("address",[]),i.pure.u64(e.minAmountOut),await eF(i)]});return await eB(i,e,a)};let eO=new y({network:T.MAINNET,fullNodeUrl:B("mainnet")});function eS(){return eO}async function ex(e,t){let{inheritTx:n,sender:i,feeAmount:o,suiInputAmount:a}=e,s=n||new r;s.setGasBudget(o);let{objectCoins:u}=await eb(t,i,(BigInt(a||"0")+o).toString(),em);return s.setGasPayment(u.map(e=>({objectId:e.coinObjectId,version:e.version,digest:e.digest}))),s}(D=Q||(Q={})).getCurveAmountAfterBuy=async function(e){let{suiAmount:t,poolId:n,frontendFee:i}=e;t=ec(t,i);let{memeAmountOut:r}=await eS().quotePump({pool:n,amount:t});return r},D.getSuiAmountAfterSell=async function(e){let{curveAmount:t,poolId:n,frontendFee:i}=e,{quoteAmountOut:r}=await eS().quoteDump({pool:n,amount:t});return ec(r,i)};var ek=ee||(ee={});async function eR(e,t){let{tx:n,coinOut:i}=await ew(e,t);I(i,"Coin out is required");let{memeCoin:r,tx:o}=await eS().pump({pool:e.poolId,quoteCoin:i,minAmountOut:e.minAmountOut,tx:n});return{tx:o,coinOut:r}}async function eE(e,t){I(eC(e.outCoinType),"Output must be SUI");let{tx:n,coinData:i}=await ey({amount:e.inputAmount,coinType:e.inCoinType,inheritTx:e.extendTx?.tx,account:e.accountAddress,splits:[e.inputAmount]},t),[r]=i,{quoteCoin:o,tx:a}=await eS().dump({pool:e.poolId,memeCoin:r,tx:n,minAmountOut:e.minAmountOut});return await eB(a,e,o)}ek.buildBuyTx=eR,ek.buildSellTx=eE,ek.getBuyTransaction=async function({coinInAmount:e,coinInType:t,coinOutType:n,poolId:i,slippage:r,walletAddress:a,tradeFee:s},u){I(eC(t),"coinInType must be SUI for buy transaction"),I(n!==t,"coinOutType must be different from coinInType"),I(r>=0&&r<1,"slippage must be between 0 (inclusive) and 1 (exclusive)"),I(e>0,"coinInAmount must be greater than 0");let l=BigInt(new o((await Q.getCurveAmountAfterBuy({poolId:i,suiAmount:e,frontendFee:s?s.tradeFeePercent:void 0})).toString()).multipliedBy(1-r).toFixed(0,3)),{tx:c,coinOut:d}=await eR({accountAddress:a,inCoinType:t,outCoinType:n,inputAmount:e.toString(),minAmountOut:l.toString(),poolId:i,frontendFee:s?s.tradeFeePercent:void 0,frontendFeeRecipient:s?s.tradeFeeRecipientAddress:void 0,extendTx:void 0,isSponsored:!1},u);I(d,"Coin out is required"),c.transferObjects([d],c.pure.address(a)),c.setSender(a);let g=await ed(u,c,a,0);return(c=await ex({inheritTx:c,sender:a,feeAmount:g,suiInputAmount:e},u)).build({client:u})},ek.getSellTransaction=async function({coinInAmount:e,coinInType:t,coinOutType:n,poolId:i,slippage:r,walletAddress:a,tradeFee:s},u){I(eC(n),"coinOutType must be SUI for sell transaction"),I(n!==t,"coinOutType must be different from coinInType"),I(r>=0&&r<1,"slippage must be between 0 (inclusive) and 1 (exclusive)"),I(e>0,"coinInAmount must be greater than 0");let l=BigInt(new o((await Q.getSuiAmountAfterSell({poolId:i,curveAmount:e,frontendFee:s?s.tradeFeePercent:void 0})).toString()).multipliedBy(1-r).toFixed(0,3)),{tx:c,coinOut:d}=await eE({accountAddress:a,inCoinType:t,outCoinType:n,inputAmount:e.toString(),minAmountOut:l.toString(),poolId:i,frontendFee:s?s.tradeFeePercent:void 0,frontendFeeRecipient:s?s.tradeFeeRecipientAddress:void 0,extendTx:void 0,isSponsored:!1},u);I(d,"Coin out is required"),c.transferObjects([d],c.pure.address(a)),c.setSender(a);let g=await ed(u,c,a,0);return(c=await ex({inheritTx:c,sender:a,feeAmount:g},u)).build({client:u})};var eP=((N={}).BLAST_FUN="BLAST_FUN",N.MOONBAGS="MOONBAGS",N);(U=et||(et={})).PACKAGE_ID="0xb8df325010942634a4afb3db3901ee215546af43a4ec4af781e7213b0bba7290",U.CONFIG_OBJECT_ID="0x74aecf86067c6913960ba4925333aefd2b1f929cafca7e21fd55a8f244b70499",U.LOCK_CONFIG_OBJECT_ID="0xfb09822d9808980abd04c51321adb850701f5f55535c6206658ef4d910c3e9be",U.BURN_MANAGER_OBJECT_ID="0x1d94aa32518d0cb00f9de6ed60d450c9a2090761f326752ffad06b2e9404f845",U.POOLS_OBJECT_ID="0xf699e7f2276f5c9a75944b37a0c5b5d9ddfd2471bf6242483b03ab2887d198d0",U.GLOBAL_CONFIG_OBJECT_ID="0xdaa46292632c3c4d8f31f23ea0f9b36a28ff3677e9684980e4438403a67a3d8f",U.FEE_DENOMINATOR=BigInt(1e4),(G=(K=en||(en={})).Curves||(K.Curves={})).calculateAddLiquidityCost=function(e,t,n){return e*t/(t-n)-e},G.calculateRemoveLiquidityReturn=function(e,t,n){return t-e*t/(e+n)},G.calculateTokenAmountReceived=function(e,t,n){return t-e*t/(e+n)},(q=K.Moonbags||(K.Moonbags={})).getDynamicVirtualTokenReserves=async function(e,t){let n=await e.getDynamicFieldObject({parentId:t,name:{type:"vector<u8>",value:"virtual_token_reserves"}});if(n.data)return BigInt(n.data.content.fields.value)},q.buyExactInReturnsWithLock=function(e){let{inputAmount:t,amountIn:n,pool:i,config:r,dynamicVirtualTokenReserves:o}=e,a=BigInt(i.virtual_sui_reserves),s=BigInt(i.virtual_token_reserves),u=BigInt(i.remain_token_reserves.fields.balance),l=K.Curves.calculateRemoveLiquidityReturn(a,s,n),c=s-(o||u),d=l,g=n;l>c&&(d=c,g=K.Curves.calculateAddLiquidityCost(a,s,c)+BigInt(1));let p=g*BigInt(r.platform_fee)/et.FEE_DENOMINATOR;return I(t>=g+p,"Input amount is less than used SUI + fee"),{receivedCurve:d,receivedSui:t-g-p}},q.sellReturns=function(e){let{amountIn:t,pool:n,config:i}=e,r=BigInt(n.virtual_sui_reserves),o=BigInt(n.virtual_token_reserves),a=BigInt(n.real_sui_reserves.fields.balance),s=K.Curves.calculateRemoveLiquidityReturn(o,r,t);s>a&&(s=a);let u=s*BigInt(i.platform_fee)/et.FEE_DENOMINATOR,l=s-u;return{receivedCurve:BigInt(0),receivedSui:l}},($=ei||(ei={})).getCurveAmountAfterBuy=async function(e,t){let{suiAmount:n,poolId:i,frontendFee:r}=e,[o,a,s]=await Promise.all([es(t,i),es(t,et.CONFIG_OBJECT_ID),en.Moonbags.getDynamicVirtualTokenReserves(t,i)]);void 0!==r&&(n=ec(n,r));let u=n*et.FEE_DENOMINATOR/(et.FEE_DENOMINATOR+BigInt(a.platform_fee)),{receivedCurve:l}=en.Moonbags.buyExactInReturnsWithLock({inputAmount:n,amountIn:u,pool:o,config:a,dynamicVirtualTokenReserves:s});return l},$.getSuiAmountAfterSell=async function(e,t){let{curveAmount:n,poolId:i,frontendFee:r}=e,[o,a]=await Promise.all([es(t,i),es(t,et.CONFIG_OBJECT_ID)]),{receivedSui:s}=en.Moonbags.sellReturns({amountIn:n,pool:o,config:a});return void 0!==r?ec(s,r):s},$.getUsedSuiForTx=async function(e,t){let{suiAmount:n,frontendFee:i}=e,r=await es(t,et.CONFIG_OBJECT_ID);return void 0!==i&&(n=ec(n,i)),n*et.FEE_DENOMINATOR/(et.FEE_DENOMINATOR+BigInt(r.platform_fee))};var eM=er||(er={});async function ej(e,t){let{tx:n,coinOut:i}=await ew(e,t);I(i,"Coin out is required");let r=await ei.getUsedSuiForTx({suiAmount:BigInt(e.inputAmount),frontendFee:e.frontendFee},t),[o,a]=n.moveCall({target:`${et.PACKAGE_ID}::moonbags::buy_exact_in_returns_with_lock`,typeArguments:[e.outCoinType],arguments:[n.object(et.CONFIG_OBJECT_ID),n.object(et.LOCK_CONFIG_OBJECT_ID),i,n.pure.u64(r),n.pure.u64(e.minAmountOut),n.object(et.BURN_MANAGER_OBJECT_ID),n.object(et.POOLS_OBJECT_ID),n.object(et.GLOBAL_CONFIG_OBJECT_ID),n.object(e_),n.object(eI)]});return Z.transferOrDestroyZeroCoin(n,em,o,e.accountAddress),{tx:n,coinOut:a}}async function eD(e,t){I(eC(e.outCoinType),"Output must be SUI");let{tx:n,coinData:i}=await ey({amount:e.inputAmount,coinType:e.inCoinType,inheritTx:e.extendTx?.tx,account:e.accountAddress,splits:[e.inputAmount]},t),[r]=i,[o,a]=n.moveCall({target:`${et.PACKAGE_ID}::moonbags::sell_returns`,typeArguments:[e.inCoinType],arguments:[n.object(et.CONFIG_OBJECT_ID),r,n.pure.u64(e.minAmountOut),n.object(eI)]});return Z.transferOrDestroyZeroCoin(n,e.inCoinType,a,e.accountAddress),await eB(n,e,o)}function eN(e){return e}function eU(e){return e}function eK(e){return new Proxy(e,{get(e,t){let n=e[t];return"function"==typeof n?n.bind(e):n}})}eM.buildBuyTx=ej,eM.buildSellTx=eD,eM.getBuyTransaction=async function({coinInAmount:e,coinInType:t,coinOutType:n,poolId:i,slippage:r,walletAddress:a,tradeFee:s},u){I(eC(t),"coinInType must be SUI for buy transaction"),I(n!==t,"coinOutType must be different from coinInType"),I(r>=0&&r<1,"slippage must be between 0 (inclusive) and 1 (exclusive)"),I(e>0,"coinInAmount must be greater than 0");let l=BigInt(new o((await ei.getCurveAmountAfterBuy({poolId:i,suiAmount:e,frontendFee:s?s.tradeFeePercent:void 0},u)).toString()).multipliedBy(1-r).toFixed(0,3)),{tx:c,coinOut:d}=await ej({accountAddress:a,inCoinType:t,outCoinType:n,inputAmount:e.toString(),minAmountOut:l.toString(),poolId:i,frontendFee:s?s.tradeFeePercent:void 0,frontendFeeRecipient:s?s.tradeFeeRecipientAddress:void 0,extendTx:void 0,isSponsored:!1},u);I(d,"Coin out is required"),c.transferObjects([d],c.pure.address(a)),c.setSender(a);let g=await ed(u,c,a,0);return(c=await ex({inheritTx:c,sender:a,feeAmount:g,suiInputAmount:e},u)).build({client:u})},eM.getSellTransaction=async function({coinInAmount:e,coinInType:t,coinOutType:n,poolId:i,slippage:r,walletAddress:a,tradeFee:s},u){I(eC(n),"coinOutType must be SUI for sell transaction"),I(n!==t,"coinOutType must be different from coinInType"),I(r>=0&&r<1,"slippage must be between 0 (inclusive) and 1 (exclusive)"),I(e>0,"coinInAmount must be greater than 0");let l=BigInt(new o((await ei.getSuiAmountAfterSell({poolId:i,curveAmount:e,frontendFee:s?s.tradeFeePercent:void 0},u)).toString()).multipliedBy(1-r).toFixed(0,3)),{tx:c,coinOut:d}=await eD({accountAddress:a,inCoinType:t,outCoinType:n,inputAmount:e.toString(),minAmountOut:l.toString(),poolId:i,frontendFee:s?s.tradeFeePercent:void 0,frontendFeeRecipient:s?s.tradeFeeRecipientAddress:void 0,extendTx:void 0,isSponsored:!1},u);I(d,"Coin out is required"),c.transferObjects([d],c.pure.address(a)),c.setSender(a);let g=await ed(u,c,a,0);return(c=await ex({inheritTx:c,sender:a,feeAmount:g},u)).build({client:u})};class eG{sdk;_astrosAggregator;_aftermathAggregator;_sevenkAggregator;_cetusAggregator;_flowXAggregator;constructor(e){this.sdk=e,this._astrosAggregator=new S({defaultTradeFee:e.options.tradeFee,astrosApiKey:e.options.astrosApiKey},e.suiClient),this._aftermathAggregator=new O({defaultTradeFee:e.options.tradeFee,aftermathApiKey:e.options.aftermathApiKey,aftermathApiEndpoint:e.options.aftermathApiEndpoint},e.suiClient),this._sevenkAggregator=new F({defaultTradeFee:e.options.tradeFee,sevenKApiKey:e.options.sevenKApiKey},e.suiClient),this._cetusAggregator=new x({defaultTradeFee:e.options.tradeFee,cetusApiKey:e.options.cetusApiKey,cetusApiEndpoint:e.options.cetusApiEndpoint,cetusPartnerId:e.options.cetusPartnerId},e.suiClient),this._flowXAggregator=new ea({defaultTradeFee:e.options.tradeFee,flowxApiKey:e.options.flowxApiKey},e.suiClient)}get astrosAggregator(){return this._astrosAggregator}get aftermathAggregator(){return this._aftermathAggregator}get sevenkAggregator(){return this._sevenkAggregator}get cetusAggregator(){return this._cetusAggregator}get flowXAggregator(){return this._flowXAggregator}async getTradeRoute(e,t){let n;switch(e){case eo.ASTROS:{let e,i=await this._astrosAggregator.getTradeRoute(t);if(!i)return null;let r=S.toCommonTradeRoutes(i,t.coinInType,t.coinOutType);if(!r)return null;e=t.tradeFee?t.tradeFee.tradeFeePercent:this.sdk.options.tradeFee.tradeFeePercent,r.amountOut=BigInt(new o(i.amount_out).multipliedBy(1-e).toFixed(0,3)),n={route:r,aggregatorRoute:i};break}case eo.AFTERMATH:{let e=await this._aftermathAggregator.getTradeRoute(t);if(!e)return null;let i=O.toCommonTradeRoutes(e);if(!i)return null;n={route:i,aggregatorRoute:e};break}case eo.SEVENK:{let e=await this._sevenkAggregator.getTradeRoute(t);if(!e)return null;let i=F.toCommonTradeRoutes(e);if(!i)return null;n={route:i,aggregatorRoute:e};break}case eo.CETUS:{let e=await this._cetusAggregator.getTradeRoute(t);if(!e)return null;let i=x.toCommonTradeRoutes(e,t.coinInType,t.coinOutType);if(!i)return null;n={route:i,aggregatorRoute:e};break}case eo.FLOWX:{let e=await this._flowXAggregator.getTradeRoute(t);if(!e)return null;let i=ea.toCommonTradeRoutes(e);if(!i)return null;n={route:i,aggregatorRoute:e}}}return n}async getTransactionByRoute(e,t){switch(e){case eo.ASTROS:return this._astrosAggregator.getTransaction({walletAddress:t.walletAddress,completeRoute:t.completeRoute,slippage:t.slippage,tradeFee:t.tradeFee});case eo.AFTERMATH:return this._aftermathAggregator.getTransaction({walletAddress:t.walletAddress,completeRoute:t.completeRoute,slippage:t.slippage});case eo.SEVENK:return this._sevenkAggregator.getTransaction({walletAddress:t.walletAddress,completeRoute:t.completeRoute,slippage:t.slippage,tradeFee:t.tradeFee});case eo.CETUS:return this._cetusAggregator.getTransaction({walletAddress:t.walletAddress,completeRoute:t.completeRoute,slippage:t.slippage,tradeFee:t.tradeFee});case eo.FLOWX:return this._flowXAggregator.getTransaction({walletAddress:t.walletAddress,completeRoute:t.completeRoute,slippage:t.slippage,tradeFee:t.tradeFee})}}async getTradeTransaction(e,t){let n=await this.getTradeRoute(e,{coinInAmount:t.coinInAmount,coinInType:t.coinInType,coinOutType:t.coinOutType,tradeFee:t.tradeFee});if(!n)return null;let i=await this.getTransactionByRoute(e,{walletAddress:t.walletAddress,completeRoute:n.aggregatorRoute,slippage:t.slippage,tradeFee:t.tradeFee});return{route:n.route,aggregatorRoute:n.aggregatorRoute,transaction:i}}async getTradeTransactionWithBestRate(e){let t=Object.keys(eo),n=await Promise.all(t.map(async t=>{try{return await this.getTradeRoute(t,e)}catch{return null}})),i=null,r=null;for(let e=0;e<n.length;e++){let o=n[e],a=t[e];if(o&&(!i||o.route.amountOut>i.route.amountOut)){i=o,r=a;continue}}if(!i||!r)return null;let o=await this.getTransactionByRoute(r,{walletAddress:e.walletAddress,completeRoute:i.aggregatorRoute,slippage:e.slippage,tradeFee:e.tradeFee});return{route:i.route,aggregatorRoute:i.aggregatorRoute,transaction:o}}async getAmountOut(e,t){let n=await this.getTradeRoute(e,t);return n?n.route.amountOut:null}async getBestAmountOut(e){let t=Object.keys(eo),n=null,i=null;for(let r of t){let t=await this.getAmountOut(r,e);null!==t&&(null===n||t>n)&&(n=t,i=r)}return null===n||null===i?null:{amountOut:n,aggregator:i}}}let eq="0x25fa0eb553dd69fa6a8028f73a38f1df7f289fa88a58ed3d7dc5a5360155bb19",e$="0x8b1a8ac6e34688cd8f8f8e5fefa9d5fb9e1ff74d2f132f8e208ae5ac9cc530bb",eL="0x13d101f44a0710a5475bec5f492a87b80e03d92d1cf540f26096f65850b23d26";class ez{sdk;constructor(e){this.sdk=e}async getConfig(){let e=await this.sdk.suiClient.getObject({id:e$,options:{showContent:!0}});I(e.data?.content,"Config object not found or has no content"),I(e.data?.content.dataType==="moveObject","Config object is not a Move object");let t=e.data.content.fields,n=t.id.id,i=t.fee_receiver,r=t.tiers.fields.contents,o={};for(let e of r){let t=e.fields.key,n=e.fields.value.fields.duration,i=e.fields.value.fields.amount,r=e.fields.value.fields.point,a=e.fields.value.fields.original_amount;o[t]={duration:BigInt(n),amount:BigInt(i),point:BigInt(r),originalAmount:BigInt(a)}}return{id:n,receiverAddress:i,tiers:o}}async buildPayBoostingTx({walletAddress:e,tierId:t,boostingCoinType:n,currentTx:i}){let o=await this.getConfig();I(t in o.tiers,"Invalid tier ID");let a=o.tiers[t].amount,s=i||new r,u=s.splitCoins(s.gas,[s.pure.u64(a)]);s.moveCall({target:`${eq}::boosting::pay`,typeArguments:[b(n)],arguments:[s.object(e$),s.pure.u64(t),u]}),s.setSender(e);let l=await ed(this.sdk.suiClient,s,e,0);return ex({inheritTx:s,sender:e,feeAmount:l},this.sdk.suiClient)}async buildAddTierTx({adminAddress:e,tierId:t,duration:n,point:i,originalAmount:o,amount:a,currentTx:s}){let u=s||new r;u.moveCall({target:`${eq}::config::add_tier`,typeArguments:[],arguments:[u.object(e$),u.object(eL),u.pure.u64(t),u.pure.u64(i),u.pure.u64(n),u.pure.u64(o),u.pure.u64(a)]}),u.setSender(e);let l=await ed(this.sdk.suiClient,u,e,0);return ex({inheritTx:u,sender:e,feeAmount:l},this.sdk.suiClient)}async buildUpdateTierTx({adminAddress:e,tierId:t,duration:n,amount:i,originalAmount:o,point:a,currentTx:s}){let u=s||new r;u.moveCall({target:`${eq}::config::update_tier`,typeArguments:[],arguments:[u.object(e$),u.object(eL),u.pure.u64(t),u.pure.u64(n),u.pure.u64(i),u.pure.u64(a),u.pure.u64(o)]}),u.setSender(e);let l=await ed(this.sdk.suiClient,u,e,0);return ex({inheritTx:u,sender:e,feeAmount:l},this.sdk.suiClient)}async buildRemoveTierTx({adminAddress:e,tierId:t,currentTx:n}){let i=n||new r;i.moveCall({target:`${eq}::config::remove_tier`,typeArguments:[],arguments:[i.object(e$),i.object(eL),i.pure.u64(t)]}),i.setSender(e);let o=await ed(this.sdk.suiClient,i,e,0);return ex({inheritTx:i,sender:e,feeAmount:o},this.sdk.suiClient)}async buildUpdateFeeReceiver({adminAddress:e,newReceiverAddress:t,currentTx:n}){let i=n||new r;i.moveCall({target:`${eq}::config::update_fee_receiver`,typeArguments:[],arguments:[i.object(e$),i.object(eL),i.pure.address(t)]}),i.setSender(e);let o=await ed(this.sdk.suiClient,i,e,0);return ex({inheritTx:i,sender:e,feeAmount:o},this.sdk.suiClient)}async buildPayBoostingWithAdminTx({walletAddress:e,tierId:t,customAmount:n,boostingCoinType:i,currentTx:o}){let a=o||new r,s=a.splitCoins(a.gas,[a.pure.u64(n)]);a.moveCall({target:`${eq}::boosting::pay_with_admin`,typeArguments:[b(i)],arguments:[a.object(eL),a.object(e$),a.pure.u64(t),a.pure.u64(n),s]}),a.setSender(e);let u=await ed(this.sdk.suiClient,a,e,0);return ex({inheritTx:a,sender:e,feeAmount:u},this.sdk.suiClient)}}class eW{sdk;constructor(e){this.sdk=e}async getEstimatedAmountOut(e,t){let{coinInType:n,coinOutType:i}=t;I(n!==i,"coinInType and coinOutType must be different"),I(eC(n)||eC(i),"One of coinInType or coinOutType must be SUI");let r=eC(n);switch(e){case eP.MOONBAGS:if(r)return await ei.getCurveAmountAfterBuy({poolId:t.poolId,suiAmount:t.coinInAmount,frontendFee:t.tradeFee?t.tradeFee.tradeFeePercent:void 0},this.sdk.suiClient);return await ei.getSuiAmountAfterSell({poolId:t.poolId,curveAmount:t.coinInAmount,frontendFee:t.tradeFee?t.tradeFee.tradeFeePercent:void 0},this.sdk.suiClient);case eP.BLAST_FUN:if(r)return await Q.getCurveAmountAfterBuy({poolId:t.poolId,suiAmount:t.coinInAmount,frontendFee:t.tradeFee?t.tradeFee.tradeFeePercent:void 0});return await Q.getSuiAmountAfterSell({poolId:t.poolId,curveAmount:t.coinInAmount,frontendFee:t.tradeFee?t.tradeFee.tradeFeePercent:void 0});default:throw Error(`Unsupported bonding curve platform: ${e}`)}}async getTradeTransaction(e,t){let n,{coinInType:i,coinOutType:r}=t;I(i!==r,"coinInType and coinOutType must be different"),I(eC(i)||eC(r),"One of coinInType or coinOutType must be SUI");let o=eC(i);switch(e){case eP.MOONBAGS:n=o?await er.getBuyTransaction(t,this.sdk.suiClient):await er.getSellTransaction(t,this.sdk.suiClient);break;case eP.BLAST_FUN:n=o?await ee.getBuyTransaction(t,this.sdk.suiClient):await ee.getSellTransaction(t,this.sdk.suiClient);break;default:throw Error(`Unsupported bonding curve platform: ${e}`)}return n}}let eJ="0x5dd4286ec234c117bb9577d4eaed1885b70d73ab1d3dab2794d0ab9a2c06c4a1",eV="0x095b941beff22213fe8ccb223e4d1c5b4ede4dcd7f82ca4bb18c9a45fd3d6e20",eX="0xdc27fe8187131b7fc095fccd213b79f72312793152a2483d1f67199c390e256d",eY="0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC";class eZ{sdk;constructor(e){this.sdk=e}async getConfig(){let e=await this.sdk.suiClient.getObject({id:eV,options:{showContent:!0}});I(e.data,"Config object not found"),I(e.data.content,"Config object has no content"),I(e.data?.content.dataType==="moveObject","Config object is not a Move object");let t=e.data.content.fields,n=t.id.id,i=t.fee_receiver,r=t.paused,o=t.accepted_payment_type,a=t.plans.fields.contents,s={};for(let e of a){let t=e.fields.key,n=e.fields.value.fields.id,i=e.fields.value.fields.price,r=e.fields.value.fields.month_interval,o=e.fields.value.fields.ptype;s[t]={id:BigInt(n),price:BigInt(i),monthInterval:r,planType:o}}return{id:n,plans:s,feeReceiverWallet:i,paused:r,acceptedPaymentType:o}}async buildSubscribeCyclePlanTx({walletAddress:e,planId:t,reference:n,paymentCoinType:i=eY,currentTx:r}){let o=await this.getConfig();I(!o.paused,"Contract is paused"),I(t in o.plans,"Invalid plan ID");let a=o.plans[t].price,{tx:s,coinData:u}=await ey({account:e,amount:a.toString(),splits:[a.toString()],coinType:i,inheritTx:r},this.sdk.suiClient);s.moveCall({target:`${eJ}::subscription::subscribe_cycle_plan`,typeArguments:[i],arguments:[s.object(eV),s.pure.u64(t),s.pure.string(n),u]}),s.setSender(e);let l=await ed(this.sdk.suiClient,s,e,0);return ex({inheritTx:s,sender:e,feeAmount:l},this.sdk.suiClient)}async buildBuyMoreCUPlanTx({walletAddress:e,planId:t,reference:n,paidAmount:i,paymentCoinType:r=eY,currentTx:o}){let a=await this.getConfig();I(!a.paused,"Contract is paused"),I(t in a.plans,"Invalid plan ID");let{tx:s,coinData:u}=await ey({account:e,amount:i.toString(),splits:[i.toString()],coinType:r,inheritTx:o},this.sdk.suiClient);s.moveCall({target:`${eJ}::subscription::buy_more_cu`,typeArguments:[r],arguments:[s.object(eV),s.pure.u64(t),s.pure.string(n),s.pure.u64(i),u]}),s.setSender(e);let l=await ed(this.sdk.suiClient,s,e,0);return ex({inheritTx:s,sender:e,feeAmount:l},this.sdk.suiClient)}async buildSubscribePlanWithAdminTx({walletAddress:e,planId:t,reference:n,customAmount:i,paymentCoinType:r=eY,currentTx:o}){I(!(await this.getConfig()).paused,"Contract is paused");let{tx:a,coinData:s}=await ey({account:e,amount:i.toString(),splits:[i.toString()],coinType:r,inheritTx:o},this.sdk.suiClient);a.moveCall({target:`${eJ}::subscription::subscribe_plan_with_admin`,typeArguments:[r],arguments:[a.object(eX),a.object(eV),a.pure.u64(t),a.pure.string(n),a.pure.u64(i),s]}),a.setSender(e);let u=await ed(this.sdk.suiClient,a,e,0);return ex({inheritTx:a,sender:e,feeAmount:u},this.sdk.suiClient)}async buildAddPlanTx({adminAddress:e,planId:t,planType:n,monthInterval:i,price:o,currentTx:a}){let s=a||new r;s.moveCall({target:`${eJ}::config::add_plan`,typeArguments:[],arguments:[s.object(eV),s.object(eX),s.pure.u64(t),s.pure.u8(n),s.pure.u8(i),s.pure.u64(o)]}),s.setSender(e);let u=await ed(this.sdk.suiClient,s,e,0);return ex({inheritTx:s,sender:e,feeAmount:u},this.sdk.suiClient)}async buildUpdatePlanTx({adminAddress:e,planId:t,planType:n,monthInterval:i,price:o,currentTx:a}){let s=a||new r;s.moveCall({target:`${eJ}::config::update_plan`,typeArguments:[],arguments:[s.object(eV),s.object(eX),s.pure.u64(BigInt(t)),s.pure.u8(n),s.pure.u8(i),s.pure.u64(o)]}),s.setSender(e);let u=await ed(this.sdk.suiClient,s,e,0);return ex({inheritTx:s,sender:e,feeAmount:u},this.sdk.suiClient)}async buildRemovePlanTx({adminAddress:e,planId:t,currentTx:n}){let i=n||new r;i.moveCall({target:`${eJ}::config::remove_plan`,typeArguments:[],arguments:[i.object(eV),i.object(eX),i.pure.u64(BigInt(t))]}),i.setSender(e);let o=await ed(this.sdk.suiClient,i,e,0);return ex({inheritTx:i,sender:e,feeAmount:o},this.sdk.suiClient)}async buildUpdateFeeReceiverWalletTx({adminAddress:e,newFeeReceiverWallet:t,currentTx:n}){let i=n||new r;i.moveCall({target:`${eJ}::config::update_fee_receiver`,typeArguments:[],arguments:[i.object(eV),i.object(eX),i.pure.address(t)]}),i.setSender(e);let o=await ed(this.sdk.suiClient,i,e,0);return ex({inheritTx:i,sender:e,feeAmount:o},this.sdk.suiClient)}async buildSetPausedTx({adminAddress:e,paused:t,currentTx:n}){let i=n||new r;i.moveCall({target:`${eJ}::config::set_paused`,typeArguments:[],arguments:[i.object(eV),i.object(eX),i.pure.bool(t)]}),i.setSender(e);let o=await ed(this.sdk.suiClient,i,e,0);return ex({inheritTx:i,sender:e,feeAmount:o},this.sdk.suiClient)}async buildSetAcceptedPaymentTypeTx({adminAddress:e,paymentCoinType:t,currentTx:n}){let i=n||new r;i.moveCall({target:`${eJ}::config::set_accepted_payment_type`,typeArguments:[t],arguments:[i.object(eV),i.object(eX)]}),i.setSender(e);let o=await ed(this.sdk.suiClient,i,e,0);return ex({inheritTx:i,sender:e,feeAmount:o},this.sdk.suiClient)}}class eH{_suiClient;boostingModule;subscriptionModule;constructor(){this._suiClient=new w({url:B("mainnet")}),this.subscriptionModule=new eZ(this),this.boostingModule=new ez(this)}get suiClient(){return this._suiClient}}let eQ={tradeFeePercent:.01,tradeFeeRecipientAddress:"0xdaf1c8ed29d89cd8f217f609bad0a668fa6f158c12000bfa5f93e670c99e24ff"};class e0{options;_suiClient;aggregatorModule;curveModule;constructor(e){this.options=e,this._suiClient=new w({url:B("mainnet")}),this.aggregatorModule=new eG(this),this.curveModule=new eW(this)}get suiClient(){return this._suiClient}}class e1{suiClient;constructor(e){this.suiClient=e}validatePrivateKey(e,t){I(e?.trim(),"Private key is required");let n=v.fromSecretKey(e),i=n.getPublicKey().toSuiAddress();if(i!==t)throw Error(`Private key mismatch. Expected: ${t}, Got: ${i}`);return n}async createDraft(e,t,n){I(e?.trim(),"Sender address is required"),I(t?.trim(),"Recipient address is required"),I(e!==t,"Sender and recipient cannot be the same"),I(n>0n,"Transfer amount must be at least 1 MIST");try{let i=new r,[o]=i.splitCoins(i.gas,[n]);i.transferObjects([o],t),i.setSender(e);let a=await this.suiClient.getReferenceGasPrice();i.setGasPrice(a);let s=await ed(this.suiClient,i,e,.1);i=await ex({inheritTx:i,sender:e,feeAmount:s,suiInputAmount:n},this.suiClient);let u=await i.build({client:this.suiClient}),l=Buffer.from(u).toString("base64"),c=await i.getDigest();return{sender:e,recipient:t,amountMIST:n,txDraftBase64:l,txDigest:c}}catch(e){throw Error(`Failed to create draft transaction: ${e instanceof Error?e.message:"Unknown error"}`)}}async execute(e,t){try{I(e,"Draft transaction is required"),I(e.txDraftBase64?.trim(),"Transaction data is required");let n=this.validatePrivateKey(t,e.sender),i=C(e.txDraftBase64),{signature:r}=await n.signTransaction(i),o=await this.suiClient.executeTransactionBlock({transactionBlock:i,signature:r});return{success:!0,txDigest:o.digest,effects:o.effects}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error occurred"}}}async getTransactionStatus(e){I(e?.trim(),"Transaction digest is required");try{let t=await this.suiClient.getTransactionBlock({digest:e,options:{showEffects:!0}});if(!t?.effects?.status)return"pending";return"success"===t.effects.status.status?"success":"failure"}catch(e){if(e instanceof Error&&(e.message.includes("not found")||e.message.includes("Could not find")))return"pending";return"failure"}}}var e4=1e4;export{eL as ADMIN_CAP_ID,O as AftermathAggregator,eG as AggregatorModule,S as AstrosAggregator,eT as BLUEFIN_PACKAGE_ID,eq as BOOSTING_PACKAGE_ID,W as BlastFunConstants,Y as BlastFunCustomCalculation,H as BlastFunCustomTransaction,X as BlastFunPackage,Q as BlastFunSDKCalculation,ee as BlastFunSDKTransaction,Z as BluefinTx,ez as BoostingModule,V as Bps,eI as CLOCK_OBJECT_ID,e$ as CONFIG_ID,x as CetusAggregator,eW as CurveModule,eQ as DEFAULT_TRADE_FEE,e1 as DraftTransferTx,ea as FlowXAggregator,J as MathUtils,ei as MoonbagsCalculation,et as MoonbagsConstants,en as MoonbagsPackage,er as MoonbagsTransaction,eh as NATIVE_USDC_TOKEN_TYPE,eH as NoodlesPaySdk,e0 as NoodlesSdk,eY as PAYMENT_COIN_TYPE,eX as SUBSCRIPTION_ADMIN_CAP_ID,eV as SUBSCRIPTION_CONFIG_ID,eJ as SUBSCRIPTION_PACKAGE_ID,em as SUI_FULL_TYPE,e_ as SUI_METADATA_OBJECT_ID,ef as SUI_TYPE,F as SevenKAggregator,eZ as SubscriptionModule,eo as SupportedAggregator,eP as SupportedBondingCurve,z as TradeFeeOptions,eA as USDC_TOKEN_TYPE,eN as adaptSuiClient,eU as adaptTransaction,ex as addGasFee,eK as createCompatibleSuiClient,ec as getAmountAfterFee,eb as getCoinObjectIdsByAmount,eS as getMemezPumpSDK,eu as getMoveObject,es as getMoveObjectContent,ed as getNeededGasFee,ey as getSplitCoinForTx,el as getSplitCoinsAfterFee,eC as isSuiCoinType,ew as splitSuiCoinAfterFeeFromBuyTx,eB as splitSuiCoinAfterFeeFromSellTx,e4 as BASE_BPS};
|
|
1
|
+
import { BluefinXTx, Config, buildTx, getQuote } from "@7kprotocol/sdk-ts";
|
|
2
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
3
|
+
import bignumber from "bignumber.js";
|
|
4
|
+
import { Aftermath, Helpers } from "aftermath-ts-sdk";
|
|
5
|
+
import { buildSwapPTBFromQuote, getCoins, getQuote as astros_aggregator_sdk_getQuote } from "@naviprotocol/astros-aggregator-sdk";
|
|
6
|
+
import { AggregatorClient, Env } from "@cetusprotocol/aggregator-sdk";
|
|
7
|
+
import bn from "bn.js";
|
|
8
|
+
import { AggregatorQuoter, Coin, Commission, CommissionType, TradeBuilder } from "@flowx-finance/sdk";
|
|
9
|
+
import tiny_invariant from "@minswap/tiny-invariant";
|
|
10
|
+
import { fromBase64, normalizeStructTag } from "@mysten/sui/utils";
|
|
11
|
+
import { MemezPumpSDK } from "@interest-protocol/memez-fun-sdk";
|
|
12
|
+
import { Network } from "@interest-protocol/sui-core-sdk";
|
|
13
|
+
import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
|
|
14
|
+
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
|
|
15
|
+
|
|
16
|
+
;// CONCATENATED MODULE: external "@7kprotocol/sdk-ts"
|
|
17
|
+
|
|
18
|
+
;// CONCATENATED MODULE: external "@mysten/sui/transactions"
|
|
19
|
+
|
|
20
|
+
;// CONCATENATED MODULE: external "bignumber.js"
|
|
21
|
+
|
|
22
|
+
;// CONCATENATED MODULE: ./src/aggregator/7k.ts
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 7K Protocol DEX aggregator client for routing trades across multiple pools
|
|
28
|
+
* 7K Protocol aggregates liquidity from various DEXs to find optimal trade routes
|
|
29
|
+
*/ class _7k_SevenKAggregator {
|
|
30
|
+
/** Configuration settings for the aggregator */ _config;
|
|
31
|
+
/** Sui blockchain client */ _suiClient;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new SevenKAggregator instance
|
|
34
|
+
* @param config - Aggregator configuration including fee settings and optional API key
|
|
35
|
+
* @param suiClient - Sui client for blockchain interactions
|
|
36
|
+
*/ constructor(config, suiClient){
|
|
37
|
+
this._config = config;
|
|
38
|
+
this._suiClient = suiClient;
|
|
39
|
+
// Config will be set lazily when the module is loaded
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Finds the optimal trade route for swapping tokens using 7K Protocol
|
|
43
|
+
* @param params - Trade route parameters
|
|
44
|
+
* @param params.coinInAmount - Amount of input token to swap
|
|
45
|
+
* @param params.coinInType - Type/address of input token
|
|
46
|
+
* @param params.coinOutType - Type/address of output token
|
|
47
|
+
* @returns Promise resolving to quote response with pricing and route information, or null if no route found
|
|
48
|
+
*/ async getTradeRoute({ coinInAmount, coinInType, coinOutType, tradeFee }) {
|
|
49
|
+
try {
|
|
50
|
+
// Set API key if provided
|
|
51
|
+
if (this._config.sevenKApiKey) {
|
|
52
|
+
Config.setApiKey(this._config.sevenKApiKey);
|
|
53
|
+
}
|
|
54
|
+
const tradeFeePercent = tradeFee ? tradeFee.tradeFeePercent : this._config.defaultTradeFee.tradeFeePercent;
|
|
55
|
+
return await getQuote({
|
|
56
|
+
tokenIn: coinInType,
|
|
57
|
+
tokenOut: coinOutType,
|
|
58
|
+
amountIn: coinInAmount.toString(),
|
|
59
|
+
commissionBps: tradeFeePercent * 10000
|
|
60
|
+
});
|
|
61
|
+
} catch (_err) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Builds a transaction for executing a trade route from 7K Protocol
|
|
67
|
+
* @param params - Transaction parameters
|
|
68
|
+
* @param params.walletAddress - Address of the wallet executing the trade
|
|
69
|
+
* @param params.completeRoute - Complete quote response from getTradeRoute()
|
|
70
|
+
* @param params.slippage - Maximum acceptable slippage (e.g., 0.01 for 1%)
|
|
71
|
+
* @returns Promise resolving to built transaction bytes ready for signing and execution
|
|
72
|
+
*/ async getTransaction({ walletAddress, completeRoute, slippage, tradeFee }) {
|
|
73
|
+
let tradeFeePercent;
|
|
74
|
+
let tradeFeeRecipientAddress;
|
|
75
|
+
if (tradeFee) {
|
|
76
|
+
tradeFeePercent = tradeFee.tradeFeePercent;
|
|
77
|
+
tradeFeeRecipientAddress = tradeFee.tradeFeeRecipientAddress;
|
|
78
|
+
} else {
|
|
79
|
+
tradeFeePercent = this._config.defaultTradeFee.tradeFeePercent;
|
|
80
|
+
tradeFeeRecipientAddress = this._config.defaultTradeFee.tradeFeeRecipientAddress;
|
|
81
|
+
}
|
|
82
|
+
const transaction = await buildTx({
|
|
83
|
+
quoteResponse: completeRoute,
|
|
84
|
+
slippage,
|
|
85
|
+
accountAddress: walletAddress,
|
|
86
|
+
commission: {
|
|
87
|
+
partner: tradeFeeRecipientAddress,
|
|
88
|
+
commissionBps: tradeFeePercent * 10000
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
if (transaction.tx instanceof BluefinXTx) {
|
|
92
|
+
const newTransaction = Transaction.from(transaction.tx.txBytes);
|
|
93
|
+
return newTransaction.build({
|
|
94
|
+
client: this._suiClient
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
transaction.tx.setSender(walletAddress);
|
|
98
|
+
return transaction.tx.build({
|
|
99
|
+
client: this._suiClient
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
(function(SevenKAggregator) {
|
|
104
|
+
function toCommonTradeRoutes(tradeRouteResponse) {
|
|
105
|
+
const routes = [];
|
|
106
|
+
if (!tradeRouteResponse.routes || tradeRouteResponse.routes.length === 0) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
for (const route of tradeRouteResponse.routes){
|
|
110
|
+
const paths = [];
|
|
111
|
+
const allTokenDecimal = {};
|
|
112
|
+
for (const path of route.hops){
|
|
113
|
+
for (const t of path.pool.allTokens){
|
|
114
|
+
allTokenDecimal[t.address] = t.decimal;
|
|
115
|
+
}
|
|
116
|
+
const pathDecimalIn = allTokenDecimal[path.tokenIn] ?? 0;
|
|
117
|
+
const pathDecimalOut = allTokenDecimal[path.tokenOut] ?? 0;
|
|
118
|
+
const pathAmountIn = BigInt(new bignumber(path.tokenInAmount).multipliedBy(10 ** pathDecimalIn).toFixed(0, 3));
|
|
119
|
+
const pathAmountOut = BigInt(new bignumber(path.tokenOutAmount).multipliedBy(10 ** pathDecimalOut).toFixed(0, 3));
|
|
120
|
+
paths.push({
|
|
121
|
+
poolAddress: path.poolId,
|
|
122
|
+
coinIn: path.tokenIn,
|
|
123
|
+
coinOut: path.tokenOut,
|
|
124
|
+
amountIn: pathAmountIn,
|
|
125
|
+
amountOut: pathAmountOut
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (paths.length === 0) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const routeDecimalIn = allTokenDecimal[route.tokenIn] ?? 0;
|
|
132
|
+
const routeDecimalOut = allTokenDecimal[route.tokenOut] ?? 0;
|
|
133
|
+
const routeAmountIn = BigInt(new bignumber(route.tokenInAmount).multipliedBy(10 ** routeDecimalIn).toFixed(0, 3));
|
|
134
|
+
const routeAmountOut = BigInt(new bignumber(route.tokenOutAmount).multipliedBy(10 ** routeDecimalOut).toFixed(0, 3));
|
|
135
|
+
routes.push({
|
|
136
|
+
paths: paths,
|
|
137
|
+
coinIn: route.tokenIn,
|
|
138
|
+
coinOut: route.tokenOut,
|
|
139
|
+
amountIn: routeAmountIn,
|
|
140
|
+
amountOut: routeAmountOut
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (routes.length === 0) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
coinIn: tradeRouteResponse.tokenIn,
|
|
148
|
+
coinOut: tradeRouteResponse.tokenOut,
|
|
149
|
+
amountIn: BigInt(tradeRouteResponse.swapAmountWithDecimal),
|
|
150
|
+
amountOut: BigInt(tradeRouteResponse.returnAmountWithDecimal),
|
|
151
|
+
routes: routes
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
SevenKAggregator.toCommonTradeRoutes = toCommonTradeRoutes;
|
|
155
|
+
})(_7k_SevenKAggregator || (_7k_SevenKAggregator = {}));
|
|
156
|
+
|
|
157
|
+
;// CONCATENATED MODULE: external "aftermath-ts-sdk"
|
|
158
|
+
|
|
159
|
+
;// CONCATENATED MODULE: ./src/aggregator/aftermath.ts
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Aftermath DEX aggregator client for routing trades across multiple pools
|
|
163
|
+
*/ class aftermath_AftermathAggregator {
|
|
164
|
+
/** Configuration settings for the aggregator */ _config;
|
|
165
|
+
/** Aftermath SDK client instance (lazy-loaded on first use) */ _aftermathClient;
|
|
166
|
+
/** Sui blockchain client */ _suiClient;
|
|
167
|
+
/**
|
|
168
|
+
* Creates a new AftermathAggregator instance
|
|
169
|
+
* @param config - Aggregator configuration including optional API settings
|
|
170
|
+
* @param suiClient - Sui client for blockchain interactions
|
|
171
|
+
*/ constructor(config, suiClient){
|
|
172
|
+
this._config = config;
|
|
173
|
+
this._suiClient = suiClient;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Lazy-loads and returns the Aftermath client, initializing it on first use
|
|
177
|
+
* Handles authentication if API key is provided in config
|
|
178
|
+
* @returns Promise resolving to initialized Aftermath client
|
|
179
|
+
*/ async aftermathClient() {
|
|
180
|
+
if (this._aftermathClient) {
|
|
181
|
+
return this._aftermathClient;
|
|
182
|
+
}
|
|
183
|
+
if (this._config.aftermathApiEndpoint) {
|
|
184
|
+
this._aftermathClient = new Aftermath(this._config.aftermathApiEndpoint);
|
|
185
|
+
} else {
|
|
186
|
+
this._aftermathClient = new Aftermath("MAINNET");
|
|
187
|
+
}
|
|
188
|
+
await this._aftermathClient.init();
|
|
189
|
+
if (this._config.aftermathApiKey) {
|
|
190
|
+
const keypair = Helpers.keypairFromPrivateKey(this._config.aftermathApiKey);
|
|
191
|
+
await this._aftermathClient.Auth().init({
|
|
192
|
+
async signMessageCallback ({ message }) {
|
|
193
|
+
const { signature } = await keypair.signPersonalMessage(message);
|
|
194
|
+
return {
|
|
195
|
+
signature
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
walletAddress: keypair.toSuiAddress()
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return this._aftermathClient;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Finds the optimal trade route for swapping tokens
|
|
205
|
+
* @param params - Trade route parameters
|
|
206
|
+
* @param params.coinInAmount - Amount of input token to swap
|
|
207
|
+
* @param params.coinInType - Type/address of input token
|
|
208
|
+
* @param params.coinOutType - Type/address of output token
|
|
209
|
+
* @returns Promise resolving to complete trade route with pricing and path information
|
|
210
|
+
*/ async getTradeRoute({ coinInAmount, coinInType, coinOutType, tradeFee }) {
|
|
211
|
+
try {
|
|
212
|
+
let externalFee;
|
|
213
|
+
if (tradeFee) {
|
|
214
|
+
externalFee = {
|
|
215
|
+
recipient: tradeFee.tradeFeeRecipientAddress,
|
|
216
|
+
feePercentage: tradeFee.tradeFeePercent
|
|
217
|
+
};
|
|
218
|
+
} else {
|
|
219
|
+
externalFee = {
|
|
220
|
+
recipient: this._config.defaultTradeFee.tradeFeeRecipientAddress,
|
|
221
|
+
feePercentage: this._config.defaultTradeFee.tradeFeePercent
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const client = await this.aftermathClient();
|
|
225
|
+
return await client.Router().getCompleteTradeRouteGivenAmountIn({
|
|
226
|
+
coinInAmount,
|
|
227
|
+
coinInType,
|
|
228
|
+
coinOutType,
|
|
229
|
+
externalFee
|
|
230
|
+
});
|
|
231
|
+
} catch (_err) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Builds a transaction for executing a trade route
|
|
237
|
+
* @param params - Transaction parameters
|
|
238
|
+
* @param params.completeRoute - Complete trade route from getTradeRoute()
|
|
239
|
+
* @param params.walletAddress - Address of the wallet executing the trade
|
|
240
|
+
* @param params.slippage - Maximum acceptable slippage (e.g., 0.01 for 1%)
|
|
241
|
+
* @returns Promise resolving to built transaction bytes ready for signing and execution
|
|
242
|
+
*/ async getTransaction({ completeRoute, walletAddress, slippage }) {
|
|
243
|
+
const client = await this.aftermathClient();
|
|
244
|
+
const transaction = await client.Router().getTransactionForCompleteTradeRoute({
|
|
245
|
+
completeRoute,
|
|
246
|
+
walletAddress,
|
|
247
|
+
slippage,
|
|
248
|
+
isSponsoredTx: false
|
|
249
|
+
});
|
|
250
|
+
transaction.setSender(walletAddress);
|
|
251
|
+
return transaction.build({
|
|
252
|
+
client: this._suiClient
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
(function(AftermathAggregator) {
|
|
257
|
+
function toCommonTradeRoutes(tradeRoute) {
|
|
258
|
+
if (tradeRoute.routes.length === 0) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const routes = [];
|
|
262
|
+
for (const route of tradeRoute.routes){
|
|
263
|
+
const paths = [];
|
|
264
|
+
for (const path of route.paths){
|
|
265
|
+
paths.push({
|
|
266
|
+
poolAddress: path.poolId,
|
|
267
|
+
coinIn: path.coinIn.type,
|
|
268
|
+
coinOut: path.coinOut.type,
|
|
269
|
+
amountIn: BigInt(path.coinIn.amount),
|
|
270
|
+
amountOut: BigInt(path.coinOut.amount)
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (paths.length === 0) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
routes.push({
|
|
277
|
+
paths: paths,
|
|
278
|
+
coinIn: route.coinIn.type,
|
|
279
|
+
coinOut: route.coinOut.type,
|
|
280
|
+
amountIn: route.coinIn.amount,
|
|
281
|
+
amountOut: route.coinOut.amount
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (routes.length === 0) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
coinIn: tradeRoute.coinIn.type,
|
|
289
|
+
coinOut: tradeRoute.coinOut.type,
|
|
290
|
+
amountIn: tradeRoute.coinIn.amount,
|
|
291
|
+
amountOut: tradeRoute.coinOut.amount,
|
|
292
|
+
routes: routes
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
AftermathAggregator.toCommonTradeRoutes = toCommonTradeRoutes;
|
|
296
|
+
})(aftermath_AftermathAggregator || (aftermath_AftermathAggregator = {}));
|
|
297
|
+
|
|
298
|
+
;// CONCATENATED MODULE: external "@naviprotocol/astros-aggregator-sdk"
|
|
299
|
+
|
|
300
|
+
;// CONCATENATED MODULE: ./src/aggregator/astros.ts
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Utility function to check if a coin type is SUI
|
|
306
|
+
* @param coin - The coin type string to check
|
|
307
|
+
* @returns True if the coin is SUI, false otherwise
|
|
308
|
+
*/ function isSuiCoin(coin) {
|
|
309
|
+
return coin === "0x2::sui::SUI" || coin === "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Astros DEX aggregator client for routing trades across multiple pools
|
|
313
|
+
* Provides access to liquidity aggregation from various DEX protocols
|
|
314
|
+
*/ class astros_AstrosAggregator {
|
|
315
|
+
/** Configuration settings for the aggregator */ _config;
|
|
316
|
+
/** Sui blockchain client */ _suiClient;
|
|
317
|
+
/**
|
|
318
|
+
* Creates a new AstrosAggregator instance
|
|
319
|
+
* @param config - Aggregator configuration including optional fee settings
|
|
320
|
+
* @param suiClient - Sui client for blockchain interactions
|
|
321
|
+
*/ constructor(config, suiClient){
|
|
322
|
+
this._config = config;
|
|
323
|
+
this._suiClient = suiClient;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Finds the optimal trade route for swapping tokens using Astros aggregator
|
|
327
|
+
* @param params - Trade route parameters
|
|
328
|
+
* @param params.coinInAmount - Amount of input token to swap
|
|
329
|
+
* @param params.coinInType - Type/address of input token
|
|
330
|
+
* @param params.coinOutType - Type/address of output token
|
|
331
|
+
* @returns Promise resolving to quote with pricing and route information, or null if no route found
|
|
332
|
+
*/ async getTradeRoute({ coinInAmount, coinInType, coinOutType, tradeFee }) {
|
|
333
|
+
try {
|
|
334
|
+
let serviceFee;
|
|
335
|
+
if (tradeFee) {
|
|
336
|
+
serviceFee = {
|
|
337
|
+
fee: tradeFee.tradeFeePercent,
|
|
338
|
+
receiverAddress: tradeFee.tradeFeeRecipientAddress
|
|
339
|
+
};
|
|
340
|
+
} else {
|
|
341
|
+
serviceFee = {
|
|
342
|
+
fee: this._config.defaultTradeFee.tradeFeePercent,
|
|
343
|
+
receiverAddress: this._config.defaultTradeFee.tradeFeeRecipientAddress
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return await astros_aggregator_sdk_getQuote(coinInType, coinOutType, coinInAmount, this._config.astrosApiKey, {
|
|
347
|
+
byAmountIn: true,
|
|
348
|
+
serviceFee: serviceFee
|
|
349
|
+
});
|
|
350
|
+
} catch (_err) {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Merges multiple coin objects into a single coin for trading
|
|
356
|
+
* Optimizes coin usage by merging smaller coins into larger ones
|
|
357
|
+
* @param txb - Transaction builder instance
|
|
358
|
+
* @param coins - Array of coin objects to merge
|
|
359
|
+
* @param amount - Required amount for the trade
|
|
360
|
+
* @returns Transaction object reference for the merged coin
|
|
361
|
+
*/ returnMergedCoins(txb, coins, amount) {
|
|
362
|
+
if (coins.length < 2) {
|
|
363
|
+
return txb.object(coins[0].coinObjectId);
|
|
364
|
+
}
|
|
365
|
+
let mergedBalance = 0;
|
|
366
|
+
const mergeList = [];
|
|
367
|
+
coins.sort((a, b)=>Number(b.balance) - Number(a.balance)).slice(1).forEach((coin)=>{
|
|
368
|
+
if (mergedBalance >= amount) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
mergedBalance += Number(coin.balance);
|
|
372
|
+
mergeList.push(coin.coinObjectId);
|
|
373
|
+
});
|
|
374
|
+
const baseObj = coins[0].coinObjectId;
|
|
375
|
+
txb.mergeCoins(baseObj, mergeList);
|
|
376
|
+
return txb.object(baseObj);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Builds a transaction for executing a trade route from Astros aggregator
|
|
380
|
+
* @param params - Transaction parameters
|
|
381
|
+
* @param params.completeRoute - Complete quote from getTradeRoute() (aliased as quote)
|
|
382
|
+
* @param params.walletAddress - Address of the wallet executing the trade
|
|
383
|
+
* @param params.slippage - Maximum acceptable slippage (e.g., 0.01 for 1%)
|
|
384
|
+
* @returns Promise resolving to built transaction bytes ready for signing and execution
|
|
385
|
+
*/ async getTransaction({ completeRoute: quote, walletAddress, slippage, tradeFee }) {
|
|
386
|
+
let serviceFee;
|
|
387
|
+
if (tradeFee) {
|
|
388
|
+
serviceFee = {
|
|
389
|
+
fee: tradeFee.tradeFeePercent,
|
|
390
|
+
receiverAddress: tradeFee.tradeFeeRecipientAddress
|
|
391
|
+
};
|
|
392
|
+
} else {
|
|
393
|
+
serviceFee = {
|
|
394
|
+
fee: this._config.defaultTradeFee.tradeFeePercent,
|
|
395
|
+
receiverAddress: this._config.defaultTradeFee.tradeFeeRecipientAddress
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
const minAmountOut = new bignumber(quote.amount_out).multipliedBy(1 - slippage - serviceFee.fee).toNumber();
|
|
399
|
+
const txb = new Transaction();
|
|
400
|
+
let coinIn;
|
|
401
|
+
if (isSuiCoin(quote.from)) {
|
|
402
|
+
coinIn = txb.splitCoins(txb.gas, [
|
|
403
|
+
txb.pure.u64(quote.amount_in)
|
|
404
|
+
]);
|
|
405
|
+
} else {
|
|
406
|
+
const coins = await getCoins(this._suiClient, walletAddress, quote.from);
|
|
407
|
+
const mergedCoins = this.returnMergedCoins(txb, coins.data, Number.parseFloat(quote.amount_in));
|
|
408
|
+
coinIn = txb.splitCoins(mergedCoins, [
|
|
409
|
+
txb.pure.u64(quote.amount_in)
|
|
410
|
+
]);
|
|
411
|
+
}
|
|
412
|
+
const coinB = await buildSwapPTBFromQuote(walletAddress, txb, minAmountOut, coinIn, quote, undefined, false, this._config.astrosApiKey, {
|
|
413
|
+
serviceFee: serviceFee
|
|
414
|
+
});
|
|
415
|
+
txb.transferObjects([
|
|
416
|
+
coinB
|
|
417
|
+
], walletAddress);
|
|
418
|
+
txb.setSender(walletAddress);
|
|
419
|
+
return txb.build({
|
|
420
|
+
client: this._suiClient
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
(function(AstrosAggregator) {
|
|
425
|
+
function toCommonTradeRoutes(tradeRoute, coinInType, coinOutType) {
|
|
426
|
+
if (tradeRoute.routes.length === 0) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
const routes = [];
|
|
430
|
+
for (const route of tradeRoute.routes){
|
|
431
|
+
const paths = [];
|
|
432
|
+
for (const path of route.path){
|
|
433
|
+
paths.push({
|
|
434
|
+
poolAddress: path.id,
|
|
435
|
+
coinIn: path.from,
|
|
436
|
+
coinOut: path.target,
|
|
437
|
+
amountIn: BigInt(path.amount_in),
|
|
438
|
+
amountOut: BigInt(path.amount_out)
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
if (paths.length === 0) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
routes.push({
|
|
445
|
+
amountIn: BigInt(route.amount_in),
|
|
446
|
+
amountOut: BigInt(route.amount_out),
|
|
447
|
+
coinIn: paths[0].coinIn,
|
|
448
|
+
coinOut: paths[paths.length - 1].coinOut,
|
|
449
|
+
paths: paths
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
if (routes.length === 0) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
coinIn: coinInType,
|
|
457
|
+
coinOut: coinOutType,
|
|
458
|
+
amountIn: BigInt(tradeRoute.amount_in),
|
|
459
|
+
amountOut: BigInt(tradeRoute.amount_out),
|
|
460
|
+
routes: routes
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
AstrosAggregator.toCommonTradeRoutes = toCommonTradeRoutes;
|
|
464
|
+
})(astros_AstrosAggregator || (astros_AstrosAggregator = {}));
|
|
465
|
+
|
|
466
|
+
;// CONCATENATED MODULE: external "@cetusprotocol/aggregator-sdk"
|
|
467
|
+
|
|
468
|
+
;// CONCATENATED MODULE: external "bn.js"
|
|
469
|
+
|
|
470
|
+
;// CONCATENATED MODULE: ./src/fee/types.ts
|
|
471
|
+
/**
|
|
472
|
+
* Configuration options for trade fees applied to aggregator transactions
|
|
473
|
+
*/ (function(TradeFeeOptions) {
|
|
474
|
+
function equals(a, b) {
|
|
475
|
+
return a.tradeFeePercent === b.tradeFeePercent && a.tradeFeeRecipientAddress === b.tradeFeeRecipientAddress;
|
|
476
|
+
}
|
|
477
|
+
TradeFeeOptions.equals = equals;
|
|
478
|
+
})(types_TradeFeeOptions || (types_TradeFeeOptions = {}));
|
|
479
|
+
var types_TradeFeeOptions;
|
|
480
|
+
|
|
481
|
+
;// CONCATENATED MODULE: ./src/aggregator/cetus.ts
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Cetus DEX aggregator client for routing trades across multiple pools
|
|
488
|
+
* Cetus is a concentrated liquidity protocol that provides efficient trading
|
|
489
|
+
*/ class cetus_CetusAggregator {
|
|
490
|
+
/** Configuration settings for the aggregator */ _config;
|
|
491
|
+
/** Sui blockchain client */ _suiClient;
|
|
492
|
+
/** Cetus aggregator client instance (lazy-loaded) */ _cetusClient;
|
|
493
|
+
/**
|
|
494
|
+
* Creates a new CetusAggregator instance
|
|
495
|
+
* @param config - Aggregator configuration including fee settings and optional API credentials
|
|
496
|
+
* @param suiClient - Sui client for blockchain interactions
|
|
497
|
+
*/ constructor(config, suiClient){
|
|
498
|
+
this._config = config;
|
|
499
|
+
this._suiClient = suiClient;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Lazy-loads and returns the Cetus aggregator client, initializing it on first use
|
|
503
|
+
* Configures the client with overlay fees, API credentials, and partner information
|
|
504
|
+
* @param walletAddress - Optional wallet address for signing transactions
|
|
505
|
+
* @param tradeFee - Optional custom trade fee settings for this client instance
|
|
506
|
+
* @returns Initialized Cetus AggregatorClient instance
|
|
507
|
+
*/ cetusClient(walletAddress, tradeFee) {
|
|
508
|
+
if (tradeFee && !types_TradeFeeOptions.equals(tradeFee, this._config.defaultTradeFee)) {
|
|
509
|
+
return new AggregatorClient({
|
|
510
|
+
client: this._suiClient,
|
|
511
|
+
overlayFeeReceiver: tradeFee.tradeFeeRecipientAddress,
|
|
512
|
+
overlayFeeRate: tradeFee.tradeFeePercent,
|
|
513
|
+
env: Env.Mainnet,
|
|
514
|
+
signer: walletAddress,
|
|
515
|
+
...this._config.cetusApiKey && this._config.cetusApiEndpoint ? {
|
|
516
|
+
apiKey: this._config.cetusApiKey,
|
|
517
|
+
endpoint: this._config.cetusApiEndpoint
|
|
518
|
+
} : {},
|
|
519
|
+
partner: this._config.cetusPartnerId
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
if (this._cetusClient) {
|
|
523
|
+
return this._cetusClient;
|
|
524
|
+
}
|
|
525
|
+
this._cetusClient = new AggregatorClient({
|
|
526
|
+
client: this._suiClient,
|
|
527
|
+
overlayFeeReceiver: this._config.defaultTradeFee.tradeFeeRecipientAddress,
|
|
528
|
+
overlayFeeRate: this._config.defaultTradeFee.tradeFeePercent,
|
|
529
|
+
env: Env.Mainnet,
|
|
530
|
+
signer: walletAddress,
|
|
531
|
+
...this._config.cetusApiKey && this._config.cetusApiEndpoint ? {
|
|
532
|
+
apiKey: this._config.cetusApiKey,
|
|
533
|
+
endpoint: this._config.cetusApiEndpoint
|
|
534
|
+
} : {},
|
|
535
|
+
partner: this._config.cetusPartnerId
|
|
536
|
+
});
|
|
537
|
+
return this._cetusClient;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Finds the optimal trade route for swapping tokens using Cetus aggregator
|
|
541
|
+
* @param params - Trade route parameters
|
|
542
|
+
* @param params.coinInAmount - Amount of input token to swap
|
|
543
|
+
* @param params.coinInType - Type/address of input token
|
|
544
|
+
* @param params.coinOutType - Type/address of output token
|
|
545
|
+
* @returns Promise resolving to router data with pricing and route information, or null if no route found
|
|
546
|
+
*/ async getTradeRoute({ coinInAmount, coinInType, coinOutType, tradeFee }) {
|
|
547
|
+
try {
|
|
548
|
+
const client = this.cetusClient(undefined, tradeFee);
|
|
549
|
+
return await client.findRouters({
|
|
550
|
+
from: coinInType,
|
|
551
|
+
target: coinOutType,
|
|
552
|
+
amount: new bn(coinInAmount.toString()),
|
|
553
|
+
byAmountIn: true
|
|
554
|
+
});
|
|
555
|
+
} catch (_err) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Builds a transaction for executing a trade route from Cetus aggregator
|
|
561
|
+
* @param params - Transaction parameters
|
|
562
|
+
* @param params.completeRoute - Complete router data from getTradeRoute() (aliased as routers)
|
|
563
|
+
* @param params.walletAddress - Address of the wallet executing the trade
|
|
564
|
+
* @param params.slippage - Maximum acceptable slippage (e.g., 0.01 for 1%)
|
|
565
|
+
* @returns Promise resolving to built transaction bytes ready for signing and execution
|
|
566
|
+
*/ async getTransaction({ completeRoute: routers, walletAddress, slippage, tradeFee }) {
|
|
567
|
+
const client = this.cetusClient(walletAddress, tradeFee);
|
|
568
|
+
const txb = new Transaction();
|
|
569
|
+
txb.setSender(walletAddress);
|
|
570
|
+
await client.fastRouterSwap({
|
|
571
|
+
router: routers,
|
|
572
|
+
txb,
|
|
573
|
+
slippage
|
|
574
|
+
});
|
|
575
|
+
await client.devInspectTransactionBlock(txb);
|
|
576
|
+
return txb.build({
|
|
577
|
+
client: this._suiClient
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
(function(CetusAggregator) {
|
|
582
|
+
function toCommonTradeRoutes(tradeRoute, coinInType, coinOutType) {
|
|
583
|
+
if (tradeRoute.paths.length === 0) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
const routes = [];
|
|
587
|
+
const allPaths = [];
|
|
588
|
+
let currentRoute = [];
|
|
589
|
+
for(let i = 0; i < tradeRoute.paths.length; i++){
|
|
590
|
+
const currentPath = tradeRoute.paths[i];
|
|
591
|
+
const tradePath = {
|
|
592
|
+
poolAddress: currentPath.id,
|
|
593
|
+
amountIn: BigInt(currentPath.amountIn),
|
|
594
|
+
amountOut: BigInt(currentPath.amountOut),
|
|
595
|
+
coinIn: currentPath.from,
|
|
596
|
+
coinOut: currentPath.target
|
|
597
|
+
};
|
|
598
|
+
// Add current path to the current route
|
|
599
|
+
currentRoute.push(tradePath);
|
|
600
|
+
// Check if this is the last path or if the next path starts a new route
|
|
601
|
+
if (i === tradeRoute.paths.length - 1) {
|
|
602
|
+
// This is the last path, finish the current route
|
|
603
|
+
allPaths.push([
|
|
604
|
+
...currentRoute
|
|
605
|
+
]);
|
|
606
|
+
} else {
|
|
607
|
+
const nextPath = tradeRoute.paths[i + 1];
|
|
608
|
+
if (currentPath.target !== nextPath.from) {
|
|
609
|
+
// Next path doesn't connect, so current route is complete
|
|
610
|
+
allPaths.push([
|
|
611
|
+
...currentRoute
|
|
612
|
+
]);
|
|
613
|
+
currentRoute = []; // Start a new route
|
|
614
|
+
}
|
|
615
|
+
// If currentPath.target === nextPath.from, continue building the current route
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
for (const pathGroup of allPaths){
|
|
619
|
+
if (pathGroup.length === 0) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
routes.push({
|
|
623
|
+
amountIn: pathGroup[0].amountIn,
|
|
624
|
+
amountOut: pathGroup[pathGroup.length - 1].amountOut,
|
|
625
|
+
coinIn: pathGroup[0].coinIn,
|
|
626
|
+
coinOut: pathGroup[pathGroup.length - 1].coinOut,
|
|
627
|
+
paths: pathGroup
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
if (routes.length === 0) {
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
coinIn: coinInType,
|
|
635
|
+
coinOut: coinOutType,
|
|
636
|
+
amountIn: BigInt(tradeRoute.amountIn.toString(10)),
|
|
637
|
+
amountOut: BigInt(tradeRoute.amountOut.toString(10)),
|
|
638
|
+
routes: routes
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
CetusAggregator.toCommonTradeRoutes = toCommonTradeRoutes;
|
|
642
|
+
})(cetus_CetusAggregator || (cetus_CetusAggregator = {}));
|
|
643
|
+
|
|
644
|
+
;// CONCATENATED MODULE: ./src/aggregator/common.ts
|
|
645
|
+
var common_SupportedAggregator = /*#__PURE__*/ function(SupportedAggregator) {
|
|
646
|
+
SupportedAggregator["ASTROS"] = "ASTROS";
|
|
647
|
+
SupportedAggregator["AFTERMATH"] = "AFTERMATH";
|
|
648
|
+
SupportedAggregator["SEVENK"] = "7K";
|
|
649
|
+
SupportedAggregator["CETUS"] = "CETUS";
|
|
650
|
+
SupportedAggregator["FLOWX"] = "FLOWX";
|
|
651
|
+
return SupportedAggregator;
|
|
652
|
+
}({});
|
|
653
|
+
|
|
654
|
+
;// CONCATENATED MODULE: external "@flowx-finance/sdk"
|
|
655
|
+
|
|
656
|
+
;// CONCATENATED MODULE: ./src/aggregator/flowx.ts
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Converts percentage to FlowX's expected format (1e6 multiplier)
|
|
660
|
+
* @param percent - Percentage value (e.g., 0.01 for 1%)
|
|
661
|
+
* @returns Percentage in FlowX format (1% = 1,000,000)
|
|
662
|
+
*/ function getInputPercent(percent) {
|
|
663
|
+
return 1e6 * percent;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* FlowX DEX aggregator client for routing trades across multiple pools
|
|
667
|
+
* FlowX provides liquidity aggregation and optimized routing for Sui ecosystem
|
|
668
|
+
*/ class flowx_FlowXAggregator {
|
|
669
|
+
/** Configuration settings for the aggregator */ _config;
|
|
670
|
+
/** Sui blockchain client */ _suiClient;
|
|
671
|
+
/**
|
|
672
|
+
* Creates a new FlowXAggregator instance
|
|
673
|
+
* @param config - Aggregator configuration including fee settings and optional API key
|
|
674
|
+
* @param suiClient - Sui client for blockchain interactions
|
|
675
|
+
*/ constructor(config, suiClient){
|
|
676
|
+
this._config = config;
|
|
677
|
+
this._suiClient = suiClient;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Creates a commission configuration for FlowX trades
|
|
681
|
+
* @param coinInType - Type/address of the input coin for commission calculation
|
|
682
|
+
* @param tradeFee - Optional custom trade fee settings for this commission
|
|
683
|
+
* @returns Commission instance configured with fee recipient, percentage, and coin type
|
|
684
|
+
*/ getCommission(coinInType, tradeFee) {
|
|
685
|
+
let tradeFeePercent;
|
|
686
|
+
let tradeFeeRecipientAddress;
|
|
687
|
+
if (tradeFee) {
|
|
688
|
+
tradeFeePercent = tradeFee.tradeFeePercent;
|
|
689
|
+
tradeFeeRecipientAddress = tradeFee.tradeFeeRecipientAddress;
|
|
690
|
+
} else {
|
|
691
|
+
tradeFeePercent = this._config.defaultTradeFee.tradeFeePercent;
|
|
692
|
+
tradeFeeRecipientAddress = this._config.defaultTradeFee.tradeFeeRecipientAddress;
|
|
693
|
+
}
|
|
694
|
+
return new Commission(tradeFeeRecipientAddress, new Coin(coinInType), CommissionType.PERCENTAGE, getInputPercent(tradeFeePercent), true);
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Finds the optimal trade route for swapping tokens using FlowX aggregator
|
|
698
|
+
* @param params - Trade route parameters
|
|
699
|
+
* @param params.coinInAmount - Amount of input token to swap
|
|
700
|
+
* @param params.coinInType - Type/address of input token
|
|
701
|
+
* @param params.coinOutType - Type/address of output token
|
|
702
|
+
* @returns Promise resolving to routes result with pricing and path information, or null if no route found
|
|
703
|
+
*/ async getTradeRoute({ coinInAmount, coinInType, coinOutType, tradeFee }) {
|
|
704
|
+
const quoter = new AggregatorQuoter("mainnet", this._config.flowxApiKey);
|
|
705
|
+
try {
|
|
706
|
+
return await quoter.getRoutes({
|
|
707
|
+
tokenIn: coinInType,
|
|
708
|
+
tokenOut: coinOutType,
|
|
709
|
+
amountIn: coinInAmount.toString(),
|
|
710
|
+
commission: this.getCommission(coinInType, tradeFee)
|
|
711
|
+
});
|
|
712
|
+
} catch (_err) {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Builds a transaction for executing a trade route from FlowX aggregator
|
|
718
|
+
* @param params - Transaction parameters
|
|
719
|
+
* @param params.walletAddress - Address of the wallet executing the trade
|
|
720
|
+
* @param params.completeRoute - Complete routes result from getTradeRoute()
|
|
721
|
+
* @param params.slippage - Maximum acceptable slippage (e.g., 0.01 for 1%)
|
|
722
|
+
* @returns Promise resolving to built transaction bytes ready for signing and execution
|
|
723
|
+
*/ async getTransaction({ walletAddress, completeRoute, slippage, tradeFee }) {
|
|
724
|
+
const tradeBuilder = new TradeBuilder("mainnet", completeRoute.routes);
|
|
725
|
+
const result = tradeBuilder.sender(walletAddress).slippage(getInputPercent(slippage)).commission(this.getCommission(completeRoute.coinIn.coinType, tradeFee)).build();
|
|
726
|
+
return result.buildTransaction({
|
|
727
|
+
client: this._suiClient
|
|
728
|
+
}).then((tx)=>{
|
|
729
|
+
tx.setSender(walletAddress);
|
|
730
|
+
return tx.build({
|
|
731
|
+
client: this._suiClient
|
|
732
|
+
});
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
(function(FlowXAggregator) {
|
|
737
|
+
function toCommonTradeRoutes(tradeRoute) {
|
|
738
|
+
if (tradeRoute.routes.length === 0) {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
const routes = [];
|
|
742
|
+
for (const route of tradeRoute.routes){
|
|
743
|
+
const paths = [];
|
|
744
|
+
for (const path of route.paths){
|
|
745
|
+
paths.push({
|
|
746
|
+
amountIn: BigInt(path.amountIn.toString()),
|
|
747
|
+
amountOut: BigInt(path.amountOut.toString()),
|
|
748
|
+
coinIn: path.input.coinType,
|
|
749
|
+
coinOut: path.output.coinType,
|
|
750
|
+
poolAddress: path.pool.id
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
if (paths.length === 0) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
routes.push({
|
|
757
|
+
amountIn: BigInt(route.amountIn.toString()),
|
|
758
|
+
amountOut: BigInt(route.amountOut.toString()),
|
|
759
|
+
coinIn: route.input.coinType,
|
|
760
|
+
coinOut: route.output.coinType,
|
|
761
|
+
paths: paths
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (routes.length === 0) {
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
return {
|
|
768
|
+
coinIn: tradeRoute.coinIn.coinType,
|
|
769
|
+
coinOut: tradeRoute.coinOut.coinType,
|
|
770
|
+
amountIn: BigInt(tradeRoute.amountIn.toString()),
|
|
771
|
+
amountOut: BigInt(tradeRoute.amountOut.toString()),
|
|
772
|
+
routes: routes
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
FlowXAggregator.toCommonTradeRoutes = toCommonTradeRoutes;
|
|
776
|
+
})(flowx_FlowXAggregator || (flowx_FlowXAggregator = {}));
|
|
777
|
+
|
|
778
|
+
;// CONCATENATED MODULE: ./src/aggregator/index.ts
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/constants.ts
|
|
788
|
+
(function(BlastFunConstants) {
|
|
789
|
+
BlastFunConstants.PACKAGE_ID_V4 = "0x7e6aa6e179466ab2814425a780b122575296d011119fa69d27f289f5a28814bd";
|
|
790
|
+
BlastFunConstants.MEMEZ_AV_OBJECT_ID = "0x2319e3e76dfad73d8f4684bdbf42be4f32d8ce4521dd61becc8261dc918d82c0";
|
|
791
|
+
})(constants_BlastFunConstants || (constants_BlastFunConstants = {}));
|
|
792
|
+
var constants_BlastFunConstants;
|
|
793
|
+
|
|
794
|
+
;// CONCATENATED MODULE: external "@minswap/tiny-invariant"
|
|
795
|
+
|
|
796
|
+
;// CONCATENATED MODULE: ./src/libs/move/index.ts
|
|
797
|
+
|
|
798
|
+
async function getMoveObjectContent(suiClient, objectId) {
|
|
799
|
+
const moveObject = await getMoveObject(suiClient, objectId);
|
|
800
|
+
return moveObject.fields;
|
|
801
|
+
}
|
|
802
|
+
async function getMoveObject(suiClient, objectId) {
|
|
803
|
+
const objRes = await suiClient.getObject({
|
|
804
|
+
id: objectId,
|
|
805
|
+
options: {
|
|
806
|
+
showContent: true
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
const content = objRes.data?.content;
|
|
810
|
+
tiny_invariant(content, "Pool object not found or has no content");
|
|
811
|
+
tiny_invariant(content.dataType === "moveObject", "Object is not a Move object");
|
|
812
|
+
return content;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
;// CONCATENATED MODULE: ./src/libs/math/fee.ts
|
|
816
|
+
const BASE_BPS = 10000;
|
|
817
|
+
function getSplitCoinsAfterFee(amount, fee) {
|
|
818
|
+
const amountNum = BigInt(amount);
|
|
819
|
+
const feeNum = BigInt(Number(fee) * BASE_BPS);
|
|
820
|
+
if (feeNum === BigInt(0)) {
|
|
821
|
+
return [
|
|
822
|
+
amountNum.toString()
|
|
823
|
+
];
|
|
824
|
+
}
|
|
825
|
+
const feeAmount = amountNum * feeNum / BigInt(BASE_BPS);
|
|
826
|
+
const remainingAmount = amountNum - feeAmount;
|
|
827
|
+
return [
|
|
828
|
+
remainingAmount.toString(),
|
|
829
|
+
feeAmount.toString()
|
|
830
|
+
];
|
|
831
|
+
}
|
|
832
|
+
function getAmountAfterFee(amount, fee) {
|
|
833
|
+
if (!fee || Number(fee) <= 0) {
|
|
834
|
+
return BigInt(amount);
|
|
835
|
+
}
|
|
836
|
+
const amountNum = BigInt(amount);
|
|
837
|
+
const feeNum = BigInt(Number(fee) * BASE_BPS);
|
|
838
|
+
if (feeNum === BigInt(0)) {
|
|
839
|
+
return amountNum;
|
|
840
|
+
}
|
|
841
|
+
const feeAmount = amountNum * feeNum / BigInt(BASE_BPS);
|
|
842
|
+
return amountNum - feeAmount;
|
|
843
|
+
}
|
|
844
|
+
async function getNeededGasFee(suiClient, tx, sender, bufferPercent) {
|
|
845
|
+
const { effects: { gasUsed, status } } = await suiClient.devInspectTransactionBlock({
|
|
846
|
+
sender,
|
|
847
|
+
transactionBlock: tx
|
|
848
|
+
});
|
|
849
|
+
if (status.status !== "success") {
|
|
850
|
+
throw new Error(`Transaction failed during dev inspect: ${status.error ?? ""}`);
|
|
851
|
+
}
|
|
852
|
+
const fee = BigInt(gasUsed.computationCost) + BigInt(gasUsed.storageCost) - BigInt(gasUsed.storageRebate);
|
|
853
|
+
const feeNum = BigInt(Number(bufferPercent) * BASE_BPS);
|
|
854
|
+
return fee * (BigInt(BASE_BPS) + feeNum) / BigInt(BASE_BPS);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/package.ts
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
(function(MathUtils) {
|
|
861
|
+
(function(U64) {
|
|
862
|
+
function mulDivUp(a, b, c) {
|
|
863
|
+
let roundUp = BigInt(0);
|
|
864
|
+
if (a * b % c > BigInt(0)) {
|
|
865
|
+
roundUp = BigInt(1);
|
|
866
|
+
}
|
|
867
|
+
return a * b / c + roundUp;
|
|
868
|
+
}
|
|
869
|
+
U64.mulDivUp = mulDivUp;
|
|
870
|
+
})(MathUtils.U64 || (MathUtils.U64 = {}));
|
|
871
|
+
})(package_MathUtils || (package_MathUtils = {}));
|
|
872
|
+
(function(Bps) {
|
|
873
|
+
function calcUp(bps, amount) {
|
|
874
|
+
const bpsValue = BigInt(bps.pos0);
|
|
875
|
+
const denominator = BigInt(10000);
|
|
876
|
+
let roundUp;
|
|
877
|
+
if (bpsValue * amount % denominator !== BigInt(0)) {
|
|
878
|
+
roundUp = BigInt(1);
|
|
879
|
+
} else {
|
|
880
|
+
roundUp = BigInt(0);
|
|
881
|
+
}
|
|
882
|
+
return bpsValue * amount / denominator + roundUp;
|
|
883
|
+
}
|
|
884
|
+
Bps.calcUp = calcUp;
|
|
885
|
+
function sub(lhs, rhs) {
|
|
886
|
+
tiny_invariant(BigInt(lhs.pos0) >= BigInt(rhs.pos0), "Bps underflow");
|
|
887
|
+
return {
|
|
888
|
+
pos0: (BigInt(lhs.pos0) - BigInt(rhs.pos0)).toString()
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
Bps.sub = sub;
|
|
892
|
+
function value(bps) {
|
|
893
|
+
return BigInt(bps.pos0);
|
|
894
|
+
}
|
|
895
|
+
Bps.value = value;
|
|
896
|
+
function new_(bps) {
|
|
897
|
+
return {
|
|
898
|
+
pos0: assertOverflow(bps).toString()
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
Bps.new_ = new_;
|
|
902
|
+
function assertOverflow(bps) {
|
|
903
|
+
tiny_invariant(BigInt(bps) <= BigInt(10000), "Bps overflow");
|
|
904
|
+
return BigInt(bps);
|
|
905
|
+
}
|
|
906
|
+
Bps.assertOverflow = assertOverflow;
|
|
907
|
+
})(package_Bps || (package_Bps = {}));
|
|
908
|
+
(function(BlastFunPackage) {
|
|
909
|
+
(function(MemezFun) {
|
|
910
|
+
async function isSniperProtectedMemezFun(suiClient, poolId) {
|
|
911
|
+
const memezFun = await getMoveObjectContent(suiClient, poolId);
|
|
912
|
+
return memezFun.public_key.length > 0;
|
|
913
|
+
}
|
|
914
|
+
MemezFun.isSniperProtectedMemezFun = isSniperProtectedMemezFun;
|
|
915
|
+
})(BlastFunPackage.MemezFun || (BlastFunPackage.MemezFun = {}));
|
|
916
|
+
(function(MemezFees) {
|
|
917
|
+
function takeWithDiscount(fee, amount, discountBps) {
|
|
918
|
+
if (fee.variant === "Value") {
|
|
919
|
+
const amountRequired = BigInt(fee.fields.pos0);
|
|
920
|
+
if (amountRequired === BigInt(0)) {
|
|
921
|
+
return BigInt(0);
|
|
922
|
+
}
|
|
923
|
+
if (amount >= amountRequired) {
|
|
924
|
+
return amountRequired;
|
|
925
|
+
}
|
|
926
|
+
throw new Error(`Insufficient amount to cover fee. Required: ${amountRequired}, provided: ${amount}`);
|
|
927
|
+
} else if (fee.variant === "Percentage") {
|
|
928
|
+
const feeBps = fee.fields.pos0.fields;
|
|
929
|
+
if (BigInt(feeBps.pos0) === BigInt(0)) {
|
|
930
|
+
return BigInt(0);
|
|
931
|
+
}
|
|
932
|
+
const discountedFee = package_Bps.calcUp(package_Bps.sub(feeBps, discountBps), amount);
|
|
933
|
+
if (amount >= discountedFee) {
|
|
934
|
+
return discountedFee;
|
|
935
|
+
} else {
|
|
936
|
+
throw new Error(`Insufficient amount to cover fee. Required: ${discountedFee}, provided: ${amount}`);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
throw new Error(`Unknown fee variant`);
|
|
940
|
+
}
|
|
941
|
+
// return fee amount taken from `amount`
|
|
942
|
+
MemezFees.takeWithDiscount = takeWithDiscount;
|
|
943
|
+
function calculateWithDiscount(fee, discountBps, amount) {
|
|
944
|
+
if (fee.variant === "Value") {
|
|
945
|
+
return BigInt(fee.fields.pos0);
|
|
946
|
+
} else if (fee.variant === "Percentage") {
|
|
947
|
+
const feeBps = fee.fields.pos0.fields;
|
|
948
|
+
return package_Bps.calcUp(package_Bps.sub(feeBps, discountBps), amount);
|
|
949
|
+
}
|
|
950
|
+
throw new Error(`Unknown fee variant`);
|
|
951
|
+
}
|
|
952
|
+
MemezFees.calculateWithDiscount = calculateWithDiscount;
|
|
953
|
+
})(BlastFunPackage.MemezFees || (BlastFunPackage.MemezFees = {}));
|
|
954
|
+
(function(MemezBurner) {
|
|
955
|
+
function calculate(burner, poolMemeBalance) {
|
|
956
|
+
const burnerFee = package_Bps.value(burner.fee.fields);
|
|
957
|
+
if (burnerFee === BigInt(0) || poolMemeBalance === BigInt(0)) {
|
|
958
|
+
return package_Bps.new_(0);
|
|
959
|
+
}
|
|
960
|
+
if (poolMemeBalance >= BigInt(burner.target_liquidity)) {
|
|
961
|
+
return package_Bps.new_(0);
|
|
962
|
+
}
|
|
963
|
+
const baseBps = BigInt(10000);
|
|
964
|
+
return package_Bps.new_(package_MathUtils.U64.mulDivUp(package_Bps.value(burner.fee.fields), package_MathUtils.U64.mulDivUp(poolMemeBalance, baseBps, BigInt(burner.target_liquidity)), baseBps));
|
|
965
|
+
}
|
|
966
|
+
MemezBurner.calculate = calculate;
|
|
967
|
+
})(BlastFunPackage.MemezBurner || (BlastFunPackage.MemezBurner = {}));
|
|
968
|
+
(function(MemezPump) {
|
|
969
|
+
async function getPumpState(suiClient, memezFun) {
|
|
970
|
+
return await getMoveObjectContent(suiClient, memezFun.inner_state);
|
|
971
|
+
}
|
|
972
|
+
MemezPump.getPumpState = getPumpState;
|
|
973
|
+
function pump(pumpState, quoteAmount) {
|
|
974
|
+
const constantProduct = pumpState.constant_product.fields;
|
|
975
|
+
const quoteSwapFee = BlastFunPackage.MemezFees.takeWithDiscount(constantProduct.quote_swap_fee, quoteAmount, constantProduct.quote_referrer_fee.fields);
|
|
976
|
+
const quoteAfterFee = quoteAmount - quoteSwapFee;
|
|
977
|
+
const memeBalance = BigInt(constantProduct.meme_balance);
|
|
978
|
+
const quoteBalance = BigInt(constantProduct.quote_balance);
|
|
979
|
+
const virtualLiquidity = BigInt(constantProduct.virtual_liquidity);
|
|
980
|
+
const memeOutExpected = memeBalance * quoteAfterFee / (virtualLiquidity + quoteBalance + quoteAfterFee);
|
|
981
|
+
const memeSwapFee = BlastFunPackage.MemezFees.takeWithDiscount(constantProduct.meme_swap_fee, memeOutExpected, constantProduct.meme_referrer_fee.fields);
|
|
982
|
+
return memeOutExpected - memeSwapFee;
|
|
983
|
+
}
|
|
984
|
+
MemezPump.pump = pump;
|
|
985
|
+
function dump(pumpState, memeAmount) {
|
|
986
|
+
const constantProduct = pumpState.constant_product.fields;
|
|
987
|
+
const memeSwapFee = BlastFunPackage.MemezFees.takeWithDiscount(constantProduct.meme_swap_fee, memeAmount, constantProduct.meme_referrer_fee.fields);
|
|
988
|
+
const inputAmount = memeAmount - memeSwapFee;
|
|
989
|
+
const memeBalance = BigInt(constantProduct.meme_balance);
|
|
990
|
+
const quoteBalance = BigInt(constantProduct.quote_balance);
|
|
991
|
+
const virtualLiquidity = BigInt(constantProduct.virtual_liquidity);
|
|
992
|
+
const burnBps = BlastFunPackage.MemezBurner.calculate(constantProduct.burner.fields, quoteBalance);
|
|
993
|
+
const burnAmount = package_Bps.calcUp(burnBps, inputAmount);
|
|
994
|
+
const inputAmountAfterFee = inputAmount - (package_Bps.value(burnBps) !== BigInt(0) ? burnAmount : BigInt(0));
|
|
995
|
+
let quoteOutBeforeFee = (virtualLiquidity + quoteBalance) * inputAmountAfterFee / (memeBalance + inputAmountAfterFee);
|
|
996
|
+
if (quoteOutBeforeFee > quoteBalance) {
|
|
997
|
+
quoteOutBeforeFee = quoteBalance;
|
|
998
|
+
}
|
|
999
|
+
const quoteSwapFee = BlastFunPackage.MemezFees.takeWithDiscount(constantProduct.quote_swap_fee, quoteOutBeforeFee, constantProduct.quote_referrer_fee.fields);
|
|
1000
|
+
return quoteOutBeforeFee - quoteSwapFee;
|
|
1001
|
+
}
|
|
1002
|
+
MemezPump.dump = dump;
|
|
1003
|
+
})(BlastFunPackage.MemezPump || (BlastFunPackage.MemezPump = {}));
|
|
1004
|
+
})(package_BlastFunPackage || (package_BlastFunPackage = {}));
|
|
1005
|
+
var package_MathUtils, package_Bps, package_BlastFunPackage;
|
|
1006
|
+
|
|
1007
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/custom-calculation.ts
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
(function(BlastFunCustomCalculation) {
|
|
1011
|
+
async function getCurveAmountAfterBuy(params, suiClient) {
|
|
1012
|
+
let { suiAmount, poolId, frontendFee } = params;
|
|
1013
|
+
const memezFun = await getMoveObjectContent(suiClient, poolId);
|
|
1014
|
+
const pumpState = await package_BlastFunPackage.MemezPump.getPumpState(suiClient, memezFun);
|
|
1015
|
+
suiAmount = getAmountAfterFee(suiAmount, frontendFee);
|
|
1016
|
+
return package_BlastFunPackage.MemezPump.pump(pumpState, suiAmount);
|
|
1017
|
+
}
|
|
1018
|
+
BlastFunCustomCalculation.getCurveAmountAfterBuy = getCurveAmountAfterBuy;
|
|
1019
|
+
async function getSuiAmountAfterSell(params, suiClient) {
|
|
1020
|
+
const { curveAmount, poolId, frontendFee } = params;
|
|
1021
|
+
const memezFun = await getMoveObjectContent(suiClient, poolId);
|
|
1022
|
+
const pumpState = await package_BlastFunPackage.MemezPump.getPumpState(suiClient, memezFun);
|
|
1023
|
+
const suiAmount = package_BlastFunPackage.MemezPump.dump(pumpState, curveAmount);
|
|
1024
|
+
return getAmountAfterFee(suiAmount, frontendFee);
|
|
1025
|
+
}
|
|
1026
|
+
BlastFunCustomCalculation.getSuiAmountAfterSell = getSuiAmountAfterSell;
|
|
1027
|
+
})(custom_calculation_BlastFunCustomCalculation || (custom_calculation_BlastFunCustomCalculation = {}));
|
|
1028
|
+
var custom_calculation_BlastFunCustomCalculation;
|
|
1029
|
+
|
|
1030
|
+
;// CONCATENATED MODULE: ./src/constant/sui.ts
|
|
1031
|
+
const SUI_TYPE = "0x2::sui::SUI";
|
|
1032
|
+
const SUI_FULL_TYPE = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
|
|
1033
|
+
const USDC_TOKEN_TYPE = "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN";
|
|
1034
|
+
const NATIVE_USDC_TOKEN_TYPE = "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC";
|
|
1035
|
+
const SUI_METADATA_OBJECT_ID = "0x9258181f5ceac8dbffb7030890243caed69a9599d2886d957a9cb7656af3bdb3";
|
|
1036
|
+
const CLOCK_OBJECT_ID = "0x0000000000000000000000000000000000000000000000000000000000000006";
|
|
1037
|
+
function isSuiCoinType(coinType) {
|
|
1038
|
+
return coinType === SUI_TYPE || coinType === SUI_FULL_TYPE;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
;// CONCATENATED MODULE: external "@mysten/sui/utils"
|
|
1042
|
+
|
|
1043
|
+
;// CONCATENATED MODULE: ./src/libs/getCoinOjectIdsByAmount.ts
|
|
1044
|
+
const orderByKey = (array, key, sortBy)=>{
|
|
1045
|
+
if (!array?.length) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
let swapped;
|
|
1049
|
+
do {
|
|
1050
|
+
swapped = false;
|
|
1051
|
+
for(let i = 0; i < array.length - 1; i++){
|
|
1052
|
+
const a = BigInt(array[i][key]);
|
|
1053
|
+
const b = BigInt(array[i + 1][key]);
|
|
1054
|
+
if (sortBy === "desc" ? a < b : a > b) {
|
|
1055
|
+
const temp = array[i];
|
|
1056
|
+
array[i] = array[i + 1];
|
|
1057
|
+
array[i + 1] = temp;
|
|
1058
|
+
swapped = true;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}while (swapped);
|
|
1062
|
+
return array;
|
|
1063
|
+
};
|
|
1064
|
+
const getCoinObjectIdsByAmount = async (suiClient, address, amount, coinType)=>{
|
|
1065
|
+
let coinBalances = [];
|
|
1066
|
+
let hasNextPage = true;
|
|
1067
|
+
let nextCursor;
|
|
1068
|
+
while(hasNextPage){
|
|
1069
|
+
try {
|
|
1070
|
+
const coins = await suiClient.getCoins({
|
|
1071
|
+
owner: address,
|
|
1072
|
+
coinType,
|
|
1073
|
+
cursor: nextCursor
|
|
1074
|
+
});
|
|
1075
|
+
coinBalances = [
|
|
1076
|
+
...coinBalances,
|
|
1077
|
+
...coins.data
|
|
1078
|
+
];
|
|
1079
|
+
hasNextPage = coins.hasNextPage;
|
|
1080
|
+
nextCursor = coins.nextCursor;
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
console.error("Error fetching data:", error);
|
|
1083
|
+
hasNextPage = false;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
// sort coin balance before get object id
|
|
1087
|
+
const coinObj = orderByKey(coinBalances.map((item)=>{
|
|
1088
|
+
return {
|
|
1089
|
+
...item,
|
|
1090
|
+
balance: item.balance
|
|
1091
|
+
};
|
|
1092
|
+
}), "balance", "desc") ?? [];
|
|
1093
|
+
let balance = "0";
|
|
1094
|
+
const objectIds = [];
|
|
1095
|
+
const objectCoins = [];
|
|
1096
|
+
for (const coin of coinObj){
|
|
1097
|
+
balance = (BigInt(coin.balance) + BigInt(balance)).toString(10);
|
|
1098
|
+
objectIds.push(coin.coinObjectId);
|
|
1099
|
+
objectCoins.push(coin);
|
|
1100
|
+
if (BigInt(balance) >= BigInt(amount)) {
|
|
1101
|
+
break;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
return {
|
|
1105
|
+
objectIds,
|
|
1106
|
+
balance,
|
|
1107
|
+
objectCoins
|
|
1108
|
+
};
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
;// CONCATENATED MODULE: ./src/libs/getSplitCoinForTx.ts
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
async function getSplitCoinForTx(params, suiClient) {
|
|
1117
|
+
const { account, amount, splits, coinType, inheritTx, inspecTransaction, isSponsored = false } = params;
|
|
1118
|
+
const tx = inheritTx ?? new Transaction();
|
|
1119
|
+
const { objectIds } = await getCoinObjectIdsByAmount(suiClient, account, amount, coinType);
|
|
1120
|
+
const coinObjectId = objectIds[0];
|
|
1121
|
+
if (normalizeStructTag(coinType) === normalizeStructTag(SUI_FULL_TYPE) && !isSponsored) {
|
|
1122
|
+
let coin;
|
|
1123
|
+
if (inspecTransaction) {
|
|
1124
|
+
if (objectIds.length > 1) {
|
|
1125
|
+
tx.mergeCoins(tx.object(coinObjectId), objectIds.slice(1).map((item)=>tx.object(item)));
|
|
1126
|
+
}
|
|
1127
|
+
coin = tx.splitCoins(tx.object(coinObjectId), splits);
|
|
1128
|
+
} else {
|
|
1129
|
+
coin = tx.splitCoins(tx.gas, splits);
|
|
1130
|
+
}
|
|
1131
|
+
return {
|
|
1132
|
+
tx,
|
|
1133
|
+
coinData: coin
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
if (objectIds.length > 1) {
|
|
1137
|
+
tx.mergeCoins(tx.object(coinObjectId), objectIds.slice(1).map((item)=>tx.object(item)));
|
|
1138
|
+
}
|
|
1139
|
+
// split correct amount to swap
|
|
1140
|
+
const coinData = tx.splitCoins(tx.object(coinObjectId), splits);
|
|
1141
|
+
return {
|
|
1142
|
+
tx,
|
|
1143
|
+
coinData
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
;// CONCATENATED MODULE: ./src/constant/bluefin.ts
|
|
1148
|
+
const BLUEFIN_PACKAGE_ID = "0x62412b7268c35f3808336aee57a52836501f40b8ba5d936f8ad275e672befd04";
|
|
1149
|
+
|
|
1150
|
+
;// CONCATENATED MODULE: ./src/libs/bluefin.ts
|
|
1151
|
+
|
|
1152
|
+
(function(BluefinTx) {
|
|
1153
|
+
function transferOrDestroyZeroCoin(tx, coinType, coin, address) {
|
|
1154
|
+
tx.moveCall({
|
|
1155
|
+
target: `${BLUEFIN_PACKAGE_ID}::utils::transfer_or_destroy`,
|
|
1156
|
+
typeArguments: [
|
|
1157
|
+
coinType
|
|
1158
|
+
],
|
|
1159
|
+
arguments: [
|
|
1160
|
+
coin,
|
|
1161
|
+
tx.pure.address(address)
|
|
1162
|
+
]
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
BluefinTx.transferOrDestroyZeroCoin = transferOrDestroyZeroCoin;
|
|
1166
|
+
})(bluefin_BluefinTx || (bluefin_BluefinTx = {}));
|
|
1167
|
+
var bluefin_BluefinTx;
|
|
1168
|
+
|
|
1169
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/common/transaction.ts
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
async function splitSuiCoinAfterFeeFromBuyTx(params, suiClient) {
|
|
1175
|
+
const { inputAmount, accountAddress, frontendFee, frontendFeeRecipient, extendTx, isSponsored } = params;
|
|
1176
|
+
tiny_invariant(params.inCoinType === SUI_FULL_TYPE || params.inCoinType === SUI_TYPE, "Input must be SUI");
|
|
1177
|
+
const { tx: _tx, coinIn } = extendTx || {};
|
|
1178
|
+
const splitSui = getSplitCoinsAfterFee(inputAmount, frontendFee || "0");
|
|
1179
|
+
const tx = _tx || new Transaction();
|
|
1180
|
+
let coinData;
|
|
1181
|
+
if (coinIn) {
|
|
1182
|
+
// Must be SUI
|
|
1183
|
+
coinData = tx.splitCoins(coinIn, splitSui);
|
|
1184
|
+
bluefin_BluefinTx.transferOrDestroyZeroCoin(tx, SUI_FULL_TYPE, coinIn, accountAddress);
|
|
1185
|
+
} else {
|
|
1186
|
+
const { coinData: _data } = await getSplitCoinForTx({
|
|
1187
|
+
account: accountAddress,
|
|
1188
|
+
amount: inputAmount,
|
|
1189
|
+
splits: splitSui,
|
|
1190
|
+
coinType: SUI_FULL_TYPE,
|
|
1191
|
+
inheritTx: tx,
|
|
1192
|
+
isSponsored: isSponsored || false
|
|
1193
|
+
}, suiClient);
|
|
1194
|
+
coinData = _data;
|
|
1195
|
+
}
|
|
1196
|
+
let inputSuiCoin;
|
|
1197
|
+
if (frontendFee && frontendFeeRecipient) {
|
|
1198
|
+
const [_inputSuiCoin, frontendFeeCoin] = coinData;
|
|
1199
|
+
inputSuiCoin = _inputSuiCoin;
|
|
1200
|
+
tx.transferObjects([
|
|
1201
|
+
frontendFeeCoin
|
|
1202
|
+
], tx.pure.address(frontendFeeRecipient || accountAddress));
|
|
1203
|
+
} else {
|
|
1204
|
+
[inputSuiCoin] = coinData;
|
|
1205
|
+
}
|
|
1206
|
+
return {
|
|
1207
|
+
tx,
|
|
1208
|
+
coinOut: inputSuiCoin
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
async function splitSuiCoinAfterFeeFromSellTx(tx, params, suiCoin) {
|
|
1212
|
+
tiny_invariant(params.outCoinType === SUI_FULL_TYPE || params.outCoinType === SUI_TYPE, "Output must be SUI");
|
|
1213
|
+
if (Number(params.frontendFee || 0) <= 0) {
|
|
1214
|
+
return {
|
|
1215
|
+
tx,
|
|
1216
|
+
coinOut: suiCoin
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
const suiCoinValue = tx.moveCall({
|
|
1220
|
+
target: `0x2::coin::value`,
|
|
1221
|
+
typeArguments: [
|
|
1222
|
+
params.outCoinType
|
|
1223
|
+
],
|
|
1224
|
+
arguments: [
|
|
1225
|
+
suiCoin
|
|
1226
|
+
]
|
|
1227
|
+
});
|
|
1228
|
+
const suiCoinFeeValue = tx.moveCall({
|
|
1229
|
+
target: `${BLUEFIN_PACKAGE_ID}::math::mul_div_u64`,
|
|
1230
|
+
typeArguments: [],
|
|
1231
|
+
arguments: [
|
|
1232
|
+
suiCoinValue,
|
|
1233
|
+
tx.pure.u64(BigInt(Number(params.frontendFee || "0") * /* inlined export .BASE_BPS */ (10000))),
|
|
1234
|
+
tx.pure.u64(BigInt(/* inlined export .BASE_BPS */ (10000)))
|
|
1235
|
+
]
|
|
1236
|
+
});
|
|
1237
|
+
const suiCoinFee = tx.moveCall({
|
|
1238
|
+
target: `0x2::coin::split`,
|
|
1239
|
+
typeArguments: [
|
|
1240
|
+
params.outCoinType
|
|
1241
|
+
],
|
|
1242
|
+
arguments: [
|
|
1243
|
+
suiCoin,
|
|
1244
|
+
suiCoinFeeValue
|
|
1245
|
+
]
|
|
1246
|
+
});
|
|
1247
|
+
tx.transferObjects([
|
|
1248
|
+
suiCoinFee
|
|
1249
|
+
], tx.pure.address(params.frontendFeeRecipient || params.accountAddress));
|
|
1250
|
+
return {
|
|
1251
|
+
tx,
|
|
1252
|
+
coinOut: suiCoin
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/custom-transaction.ts
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
(function(BlastFunCustomTransaction) {
|
|
1265
|
+
async function getAllowedVersions(_tx) {
|
|
1266
|
+
const tx = _tx || new Transaction();
|
|
1267
|
+
return tx.moveCall({
|
|
1268
|
+
target: `${constants_BlastFunConstants.PACKAGE_ID_V4}::memez_allowed_versions::get_allowed_versions`,
|
|
1269
|
+
arguments: [
|
|
1270
|
+
tx.object(constants_BlastFunConstants.MEMEZ_AV_OBJECT_ID)
|
|
1271
|
+
],
|
|
1272
|
+
typeArguments: []
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
BlastFunCustomTransaction.getAllowedVersions = getAllowedVersions;
|
|
1276
|
+
async function buildBuyTx(params, suiClient) {
|
|
1277
|
+
tiny_invariant(!await package_BlastFunPackage.MemezFun.isSniperProtectedMemezFun(suiClient, params.poolId), "This coin is a sniper protected coin, please use the Blast Fun website to trade it.");
|
|
1278
|
+
const { tx, coinOut: suiCoinIn } = await splitSuiCoinAfterFeeFromBuyTx(params, suiClient);
|
|
1279
|
+
tiny_invariant(suiCoinIn, "Coin out is required");
|
|
1280
|
+
const curveCoin = tx.moveCall({
|
|
1281
|
+
target: `${constants_BlastFunConstants.PACKAGE_ID_V4}::memez_pump::pump`,
|
|
1282
|
+
typeArguments: [
|
|
1283
|
+
params.outCoinType,
|
|
1284
|
+
SUI_FULL_TYPE
|
|
1285
|
+
],
|
|
1286
|
+
arguments: [
|
|
1287
|
+
tx.object(params.poolId),
|
|
1288
|
+
suiCoinIn,
|
|
1289
|
+
tx.pure.vector("address", []),
|
|
1290
|
+
tx.pure.vector("vector<u8>", []),
|
|
1291
|
+
tx.pure.u64(params.minAmountOut),
|
|
1292
|
+
await getAllowedVersions(tx)
|
|
1293
|
+
]
|
|
1294
|
+
});
|
|
1295
|
+
return {
|
|
1296
|
+
tx,
|
|
1297
|
+
coinOut: curveCoin
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
BlastFunCustomTransaction.buildBuyTx = buildBuyTx;
|
|
1301
|
+
async function buildSellTx(params, suiClient) {
|
|
1302
|
+
tiny_invariant(params.outCoinType === SUI_FULL_TYPE || params.outCoinType === SUI_TYPE, "Output must be SUI");
|
|
1303
|
+
const memezFun = await getMoveObjectContent(suiClient, params.poolId);
|
|
1304
|
+
const { tx, coinData } = await getSplitCoinForTx({
|
|
1305
|
+
amount: params.inputAmount,
|
|
1306
|
+
coinType: params.inCoinType,
|
|
1307
|
+
inheritTx: params.extendTx?.tx,
|
|
1308
|
+
account: params.accountAddress,
|
|
1309
|
+
splits: [
|
|
1310
|
+
params.inputAmount
|
|
1311
|
+
]
|
|
1312
|
+
}, suiClient);
|
|
1313
|
+
const [inputCoin] = coinData;
|
|
1314
|
+
const [suiCoin] = tx.moveCall({
|
|
1315
|
+
target: `${constants_BlastFunConstants.PACKAGE_ID_V4}::memez_pump::dump`,
|
|
1316
|
+
typeArguments: [
|
|
1317
|
+
params.inCoinType,
|
|
1318
|
+
params.outCoinType
|
|
1319
|
+
],
|
|
1320
|
+
arguments: [
|
|
1321
|
+
tx.object(params.poolId),
|
|
1322
|
+
tx.object(memezFun.ipx_meme_coin_treasury),
|
|
1323
|
+
inputCoin,
|
|
1324
|
+
tx.pure.vector("address", []),
|
|
1325
|
+
tx.pure.u64(params.minAmountOut),
|
|
1326
|
+
await getAllowedVersions(tx)
|
|
1327
|
+
]
|
|
1328
|
+
});
|
|
1329
|
+
return await splitSuiCoinAfterFeeFromSellTx(tx, params, suiCoin);
|
|
1330
|
+
}
|
|
1331
|
+
BlastFunCustomTransaction.buildSellTx = buildSellTx;
|
|
1332
|
+
})(custom_transaction_BlastFunCustomTransaction || (custom_transaction_BlastFunCustomTransaction = {}));
|
|
1333
|
+
var custom_transaction_BlastFunCustomTransaction;
|
|
1334
|
+
|
|
1335
|
+
;// CONCATENATED MODULE: external "@interest-protocol/memez-fun-sdk"
|
|
1336
|
+
|
|
1337
|
+
;// CONCATENATED MODULE: external "@interest-protocol/sui-core-sdk"
|
|
1338
|
+
|
|
1339
|
+
;// CONCATENATED MODULE: external "@mysten/sui/client"
|
|
1340
|
+
|
|
1341
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/meme-pump-sdk.ts
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
|
|
1345
|
+
const payload = {
|
|
1346
|
+
network: Network.MAINNET,
|
|
1347
|
+
fullNodeUrl: getFullnodeUrl("mainnet")
|
|
1348
|
+
};
|
|
1349
|
+
const memezPump = new MemezPumpSDK(payload);
|
|
1350
|
+
function getMemezPumpSDK() {
|
|
1351
|
+
return memezPump;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/sdk-calculation.ts
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
(function(BlastFunSDKCalculation) {
|
|
1358
|
+
async function getCurveAmountAfterBuy(params) {
|
|
1359
|
+
let { suiAmount, poolId, frontendFee } = params;
|
|
1360
|
+
suiAmount = getAmountAfterFee(suiAmount, frontendFee);
|
|
1361
|
+
const { memeAmountOut } = await getMemezPumpSDK().quotePump({
|
|
1362
|
+
pool: poolId,
|
|
1363
|
+
amount: suiAmount
|
|
1364
|
+
});
|
|
1365
|
+
return memeAmountOut;
|
|
1366
|
+
}
|
|
1367
|
+
BlastFunSDKCalculation.getCurveAmountAfterBuy = getCurveAmountAfterBuy;
|
|
1368
|
+
async function getSuiAmountAfterSell(params) {
|
|
1369
|
+
const { curveAmount, poolId, frontendFee } = params;
|
|
1370
|
+
const { quoteAmountOut } = await getMemezPumpSDK().quoteDump({
|
|
1371
|
+
pool: poolId,
|
|
1372
|
+
amount: curveAmount
|
|
1373
|
+
});
|
|
1374
|
+
return getAmountAfterFee(quoteAmountOut, frontendFee);
|
|
1375
|
+
}
|
|
1376
|
+
BlastFunSDKCalculation.getSuiAmountAfterSell = getSuiAmountAfterSell;
|
|
1377
|
+
})(sdk_calculation_BlastFunSDKCalculation || (sdk_calculation_BlastFunSDKCalculation = {}));
|
|
1378
|
+
var sdk_calculation_BlastFunSDKCalculation;
|
|
1379
|
+
|
|
1380
|
+
;// CONCATENATED MODULE: ./src/libs/addGasFee.ts
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
async function addGasFee(params, suiClient) {
|
|
1385
|
+
const { inheritTx, sender, feeAmount, suiInputAmount } = params;
|
|
1386
|
+
const tx = inheritTx || new Transaction();
|
|
1387
|
+
tx.setGasBudget(feeAmount);
|
|
1388
|
+
const { objectCoins } = await getCoinObjectIdsByAmount(suiClient, sender, (BigInt(suiInputAmount || "0") + feeAmount).toString(), SUI_FULL_TYPE);
|
|
1389
|
+
tx.setGasPayment(objectCoins.map((c)=>({
|
|
1390
|
+
objectId: c.coinObjectId,
|
|
1391
|
+
version: c.version,
|
|
1392
|
+
digest: c.digest
|
|
1393
|
+
})));
|
|
1394
|
+
return tx;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/sdk-transaction.ts
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
|
|
1403
|
+
|
|
1404
|
+
|
|
1405
|
+
|
|
1406
|
+
(function(BlastFunSDKTransaction) {
|
|
1407
|
+
async function buildBuyTx(params, suiClient) {
|
|
1408
|
+
const { tx, coinOut: suiCoinIn } = await splitSuiCoinAfterFeeFromBuyTx(params, suiClient);
|
|
1409
|
+
tiny_invariant(suiCoinIn, "Coin out is required");
|
|
1410
|
+
const { memeCoin, tx: tx2 } = await getMemezPumpSDK().pump({
|
|
1411
|
+
pool: params.poolId,
|
|
1412
|
+
quoteCoin: suiCoinIn,
|
|
1413
|
+
minAmountOut: params.minAmountOut,
|
|
1414
|
+
tx
|
|
1415
|
+
});
|
|
1416
|
+
return {
|
|
1417
|
+
tx: tx2,
|
|
1418
|
+
coinOut: memeCoin
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
BlastFunSDKTransaction.buildBuyTx = buildBuyTx;
|
|
1422
|
+
async function buildSellTx(params, suiClient) {
|
|
1423
|
+
tiny_invariant(isSuiCoinType(params.outCoinType), "Output must be SUI");
|
|
1424
|
+
const { tx, coinData } = await getSplitCoinForTx({
|
|
1425
|
+
amount: params.inputAmount,
|
|
1426
|
+
coinType: params.inCoinType,
|
|
1427
|
+
inheritTx: params.extendTx?.tx,
|
|
1428
|
+
account: params.accountAddress,
|
|
1429
|
+
splits: [
|
|
1430
|
+
params.inputAmount
|
|
1431
|
+
]
|
|
1432
|
+
}, suiClient);
|
|
1433
|
+
const [inputCoin] = coinData;
|
|
1434
|
+
const { quoteCoin, tx: tx2 } = await getMemezPumpSDK().dump({
|
|
1435
|
+
pool: params.poolId,
|
|
1436
|
+
memeCoin: inputCoin,
|
|
1437
|
+
tx,
|
|
1438
|
+
minAmountOut: params.minAmountOut
|
|
1439
|
+
});
|
|
1440
|
+
return await splitSuiCoinAfterFeeFromSellTx(tx2, params, quoteCoin);
|
|
1441
|
+
}
|
|
1442
|
+
BlastFunSDKTransaction.buildSellTx = buildSellTx;
|
|
1443
|
+
async function getBuyTransaction({ coinInAmount, coinInType, coinOutType, poolId, slippage, walletAddress, tradeFee }, suiClient) {
|
|
1444
|
+
tiny_invariant(isSuiCoinType(coinInType), "coinInType must be SUI for buy transaction");
|
|
1445
|
+
tiny_invariant(coinOutType !== coinInType, "coinOutType must be different from coinInType");
|
|
1446
|
+
tiny_invariant(slippage >= 0 && slippage < 1, "slippage must be between 0 (inclusive) and 1 (exclusive)");
|
|
1447
|
+
tiny_invariant(coinInAmount > 0, "coinInAmount must be greater than 0");
|
|
1448
|
+
const inputAmount = coinInAmount;
|
|
1449
|
+
const outputAmount = await sdk_calculation_BlastFunSDKCalculation.getCurveAmountAfterBuy({
|
|
1450
|
+
poolId: poolId,
|
|
1451
|
+
suiAmount: inputAmount,
|
|
1452
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined
|
|
1453
|
+
});
|
|
1454
|
+
const minAmountOut = BigInt(new bignumber(outputAmount.toString()).multipliedBy(1 - slippage).toFixed(0, 3));
|
|
1455
|
+
let { tx, coinOut } = await buildBuyTx({
|
|
1456
|
+
accountAddress: walletAddress,
|
|
1457
|
+
inCoinType: coinInType,
|
|
1458
|
+
outCoinType: coinOutType,
|
|
1459
|
+
inputAmount: inputAmount.toString(),
|
|
1460
|
+
minAmountOut: minAmountOut.toString(),
|
|
1461
|
+
poolId: poolId,
|
|
1462
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined,
|
|
1463
|
+
frontendFeeRecipient: tradeFee ? tradeFee.tradeFeeRecipientAddress : undefined,
|
|
1464
|
+
extendTx: undefined,
|
|
1465
|
+
isSponsored: false
|
|
1466
|
+
}, suiClient);
|
|
1467
|
+
tiny_invariant(coinOut, "Coin out is required");
|
|
1468
|
+
tx.transferObjects([
|
|
1469
|
+
coinOut
|
|
1470
|
+
], tx.pure.address(walletAddress));
|
|
1471
|
+
tx.setSender(walletAddress);
|
|
1472
|
+
const feeAmount = await getNeededGasFee(suiClient, tx, walletAddress, 0);
|
|
1473
|
+
tx = await addGasFee({
|
|
1474
|
+
inheritTx: tx,
|
|
1475
|
+
sender: walletAddress,
|
|
1476
|
+
feeAmount,
|
|
1477
|
+
suiInputAmount: inputAmount
|
|
1478
|
+
}, suiClient);
|
|
1479
|
+
return tx.build({
|
|
1480
|
+
client: suiClient
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
BlastFunSDKTransaction.getBuyTransaction = getBuyTransaction;
|
|
1484
|
+
async function getSellTransaction({ coinInAmount, coinInType, coinOutType, poolId, slippage, walletAddress, tradeFee }, suiClient) {
|
|
1485
|
+
tiny_invariant(isSuiCoinType(coinOutType), "coinOutType must be SUI for sell transaction");
|
|
1486
|
+
tiny_invariant(coinOutType !== coinInType, "coinOutType must be different from coinInType");
|
|
1487
|
+
tiny_invariant(slippage >= 0 && slippage < 1, "slippage must be between 0 (inclusive) and 1 (exclusive)");
|
|
1488
|
+
tiny_invariant(coinInAmount > 0, "coinInAmount must be greater than 0");
|
|
1489
|
+
const inputAmount = coinInAmount;
|
|
1490
|
+
const outputAmount = await sdk_calculation_BlastFunSDKCalculation.getSuiAmountAfterSell({
|
|
1491
|
+
poolId: poolId,
|
|
1492
|
+
curveAmount: inputAmount,
|
|
1493
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined
|
|
1494
|
+
});
|
|
1495
|
+
const minAmountOut = BigInt(new bignumber(outputAmount.toString()).multipliedBy(1 - slippage).toFixed(0, 3));
|
|
1496
|
+
let { tx, coinOut } = await buildSellTx({
|
|
1497
|
+
accountAddress: walletAddress,
|
|
1498
|
+
inCoinType: coinInType,
|
|
1499
|
+
outCoinType: coinOutType,
|
|
1500
|
+
inputAmount: inputAmount.toString(),
|
|
1501
|
+
minAmountOut: minAmountOut.toString(),
|
|
1502
|
+
poolId: poolId,
|
|
1503
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined,
|
|
1504
|
+
frontendFeeRecipient: tradeFee ? tradeFee.tradeFeeRecipientAddress : undefined,
|
|
1505
|
+
extendTx: undefined,
|
|
1506
|
+
isSponsored: false
|
|
1507
|
+
}, suiClient);
|
|
1508
|
+
tiny_invariant(coinOut, "Coin out is required");
|
|
1509
|
+
tx.transferObjects([
|
|
1510
|
+
coinOut
|
|
1511
|
+
], tx.pure.address(walletAddress));
|
|
1512
|
+
tx.setSender(walletAddress);
|
|
1513
|
+
const feeAmount = await getNeededGasFee(suiClient, tx, walletAddress, 0);
|
|
1514
|
+
tx = await addGasFee({
|
|
1515
|
+
inheritTx: tx,
|
|
1516
|
+
sender: walletAddress,
|
|
1517
|
+
feeAmount
|
|
1518
|
+
}, suiClient);
|
|
1519
|
+
return tx.build({
|
|
1520
|
+
client: suiClient
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
BlastFunSDKTransaction.getSellTransaction = getSellTransaction;
|
|
1524
|
+
})(sdk_transaction_BlastFunSDKTransaction || (sdk_transaction_BlastFunSDKTransaction = {}));
|
|
1525
|
+
var sdk_transaction_BlastFunSDKTransaction;
|
|
1526
|
+
|
|
1527
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/blast-fun/index.ts
|
|
1528
|
+
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
|
|
1533
|
+
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/common/types.ts
|
|
1537
|
+
var types_SupportedBondingCurve = /*#__PURE__*/ function(SupportedBondingCurve) {
|
|
1538
|
+
SupportedBondingCurve["BLAST_FUN"] = "BLAST_FUN";
|
|
1539
|
+
SupportedBondingCurve["MOONBAGS"] = "MOONBAGS";
|
|
1540
|
+
return SupportedBondingCurve;
|
|
1541
|
+
}({});
|
|
1542
|
+
|
|
1543
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/common/index.ts
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/moonbags/constants.ts
|
|
1548
|
+
(function(MoonbagsConstants) {
|
|
1549
|
+
MoonbagsConstants.PACKAGE_ID = "0xb8df325010942634a4afb3db3901ee215546af43a4ec4af781e7213b0bba7290";
|
|
1550
|
+
MoonbagsConstants.CONFIG_OBJECT_ID = "0x74aecf86067c6913960ba4925333aefd2b1f929cafca7e21fd55a8f244b70499";
|
|
1551
|
+
MoonbagsConstants.LOCK_CONFIG_OBJECT_ID = "0xfb09822d9808980abd04c51321adb850701f5f55535c6206658ef4d910c3e9be";
|
|
1552
|
+
MoonbagsConstants.BURN_MANAGER_OBJECT_ID = "0x1d94aa32518d0cb00f9de6ed60d450c9a2090761f326752ffad06b2e9404f845";
|
|
1553
|
+
MoonbagsConstants.POOLS_OBJECT_ID = "0xf699e7f2276f5c9a75944b37a0c5b5d9ddfd2471bf6242483b03ab2887d198d0";
|
|
1554
|
+
MoonbagsConstants.GLOBAL_CONFIG_OBJECT_ID = "0xdaa46292632c3c4d8f31f23ea0f9b36a28ff3677e9684980e4438403a67a3d8f";
|
|
1555
|
+
MoonbagsConstants.FEE_DENOMINATOR = BigInt(10000);
|
|
1556
|
+
})(constants_MoonbagsConstants || (constants_MoonbagsConstants = {}));
|
|
1557
|
+
var constants_MoonbagsConstants;
|
|
1558
|
+
|
|
1559
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/moonbags/package.ts
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
(function(MoonbagsPackage) {
|
|
1563
|
+
(function(Curves) {
|
|
1564
|
+
function calculateAddLiquidityCost(tokenIn, tokenReserve, tokenAmount) {
|
|
1565
|
+
const availableReserve = tokenReserve - tokenAmount;
|
|
1566
|
+
const numerator = tokenIn * tokenReserve;
|
|
1567
|
+
const fraction = numerator / availableReserve;
|
|
1568
|
+
return fraction - tokenIn;
|
|
1569
|
+
}
|
|
1570
|
+
Curves.calculateAddLiquidityCost = calculateAddLiquidityCost;
|
|
1571
|
+
function calculateRemoveLiquidityReturn(tokenIn, tokenReserve, tokenRemoved) {
|
|
1572
|
+
const denominator = tokenIn + tokenRemoved;
|
|
1573
|
+
const fraction = tokenIn * tokenReserve / denominator;
|
|
1574
|
+
return tokenReserve - fraction;
|
|
1575
|
+
}
|
|
1576
|
+
Curves.calculateRemoveLiquidityReturn = calculateRemoveLiquidityReturn;
|
|
1577
|
+
function calculateTokenAmountReceived(tokenIn, tokenReserve, tokenOutReserve) {
|
|
1578
|
+
const denominator = tokenIn + tokenOutReserve;
|
|
1579
|
+
const fraction = tokenIn * tokenReserve / denominator;
|
|
1580
|
+
return tokenReserve - fraction;
|
|
1581
|
+
}
|
|
1582
|
+
Curves.calculateTokenAmountReceived = calculateTokenAmountReceived;
|
|
1583
|
+
})(MoonbagsPackage.Curves || (MoonbagsPackage.Curves = {}));
|
|
1584
|
+
(function(Moonbags) {
|
|
1585
|
+
async function getDynamicVirtualTokenReserves(suiClient, poolId) {
|
|
1586
|
+
const result = await suiClient.getDynamicFieldObject({
|
|
1587
|
+
parentId: poolId,
|
|
1588
|
+
name: {
|
|
1589
|
+
type: "vector<u8>",
|
|
1590
|
+
value: "virtual_token_reserves"
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
if (!result.data) {
|
|
1594
|
+
return undefined;
|
|
1595
|
+
}
|
|
1596
|
+
return BigInt(result.data.content.fields.value);
|
|
1597
|
+
}
|
|
1598
|
+
Moonbags.getDynamicVirtualTokenReserves = getDynamicVirtualTokenReserves;
|
|
1599
|
+
function buyExactInReturnsWithLock(params) {
|
|
1600
|
+
const { inputAmount, amountIn, pool, config, dynamicVirtualTokenReserves } = params;
|
|
1601
|
+
const virtualSuiReserves = BigInt(pool.virtual_sui_reserves);
|
|
1602
|
+
const virtualTokenReserves = BigInt(pool.virtual_token_reserves);
|
|
1603
|
+
const remainTokenReserves = BigInt(pool.remain_token_reserves.fields.balance);
|
|
1604
|
+
const expectedOut = MoonbagsPackage.Curves.calculateRemoveLiquidityReturn(virtualSuiReserves, virtualTokenReserves, amountIn);
|
|
1605
|
+
const availableOut = virtualTokenReserves - (dynamicVirtualTokenReserves || remainTokenReserves);
|
|
1606
|
+
let finalOut = expectedOut;
|
|
1607
|
+
let usedSui = amountIn;
|
|
1608
|
+
if (expectedOut > availableOut) {
|
|
1609
|
+
finalOut = availableOut;
|
|
1610
|
+
usedSui = MoonbagsPackage.Curves.calculateAddLiquidityCost(virtualSuiReserves, virtualTokenReserves, availableOut) + BigInt(1);
|
|
1611
|
+
}
|
|
1612
|
+
const feeAmount = usedSui * BigInt(config.platform_fee) / constants_MoonbagsConstants.FEE_DENOMINATOR;
|
|
1613
|
+
tiny_invariant(inputAmount >= usedSui + feeAmount, "Input amount is less than used SUI + fee");
|
|
1614
|
+
return {
|
|
1615
|
+
receivedCurve: finalOut,
|
|
1616
|
+
receivedSui: inputAmount - usedSui - feeAmount
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
Moonbags.buyExactInReturnsWithLock = buyExactInReturnsWithLock;
|
|
1620
|
+
function sellReturns(params) {
|
|
1621
|
+
const { amountIn, pool, config } = params;
|
|
1622
|
+
const virtualSuiReserves = BigInt(pool.virtual_sui_reserves);
|
|
1623
|
+
const virtualTokenReserves = BigInt(pool.virtual_token_reserves);
|
|
1624
|
+
const realSuiReserves = BigInt(pool.real_sui_reserves.fields.balance);
|
|
1625
|
+
let rawSuiOut = MoonbagsPackage.Curves.calculateRemoveLiquidityReturn(virtualTokenReserves, virtualSuiReserves, amountIn);
|
|
1626
|
+
if (rawSuiOut > realSuiReserves) {
|
|
1627
|
+
rawSuiOut = realSuiReserves;
|
|
1628
|
+
}
|
|
1629
|
+
const feeAmount = rawSuiOut * BigInt(config.platform_fee) / constants_MoonbagsConstants.FEE_DENOMINATOR;
|
|
1630
|
+
const finalSuiOut = rawSuiOut - feeAmount;
|
|
1631
|
+
return {
|
|
1632
|
+
receivedCurve: BigInt(0),
|
|
1633
|
+
receivedSui: finalSuiOut
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
Moonbags.sellReturns = sellReturns;
|
|
1637
|
+
})(MoonbagsPackage.Moonbags || (MoonbagsPackage.Moonbags = {}));
|
|
1638
|
+
})(package_MoonbagsPackage || (package_MoonbagsPackage = {}));
|
|
1639
|
+
var package_MoonbagsPackage;
|
|
1640
|
+
|
|
1641
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/moonbags/calculation.ts
|
|
1642
|
+
|
|
1643
|
+
|
|
1644
|
+
|
|
1645
|
+
(function(MoonbagsCalculation) {
|
|
1646
|
+
async function getCurveAmountAfterBuy(params, suiClient) {
|
|
1647
|
+
let { suiAmount, poolId, frontendFee } = params;
|
|
1648
|
+
const [poolMoveStruct, configMoveStruct, dynamicVirtualTokenReserves] = await Promise.all([
|
|
1649
|
+
getMoveObjectContent(suiClient, poolId),
|
|
1650
|
+
getMoveObjectContent(suiClient, constants_MoonbagsConstants.CONFIG_OBJECT_ID),
|
|
1651
|
+
package_MoonbagsPackage.Moonbags.getDynamicVirtualTokenReserves(suiClient, poolId)
|
|
1652
|
+
]);
|
|
1653
|
+
const pool = poolMoveStruct;
|
|
1654
|
+
const config = configMoveStruct;
|
|
1655
|
+
if (frontendFee !== undefined) {
|
|
1656
|
+
suiAmount = getAmountAfterFee(suiAmount, frontendFee);
|
|
1657
|
+
}
|
|
1658
|
+
const usedSui = suiAmount * constants_MoonbagsConstants.FEE_DENOMINATOR / (constants_MoonbagsConstants.FEE_DENOMINATOR + BigInt(config.platform_fee));
|
|
1659
|
+
const { receivedCurve } = package_MoonbagsPackage.Moonbags.buyExactInReturnsWithLock({
|
|
1660
|
+
inputAmount: suiAmount,
|
|
1661
|
+
amountIn: usedSui,
|
|
1662
|
+
pool,
|
|
1663
|
+
config,
|
|
1664
|
+
dynamicVirtualTokenReserves
|
|
1665
|
+
});
|
|
1666
|
+
return receivedCurve;
|
|
1667
|
+
}
|
|
1668
|
+
MoonbagsCalculation.getCurveAmountAfterBuy = getCurveAmountAfterBuy;
|
|
1669
|
+
async function getSuiAmountAfterSell(params, suiClient) {
|
|
1670
|
+
const { curveAmount, poolId, frontendFee } = params;
|
|
1671
|
+
const [poolMoveStruct, configMoveStruct] = await Promise.all([
|
|
1672
|
+
getMoveObjectContent(suiClient, poolId),
|
|
1673
|
+
getMoveObjectContent(suiClient, constants_MoonbagsConstants.CONFIG_OBJECT_ID)
|
|
1674
|
+
]);
|
|
1675
|
+
const pool = poolMoveStruct;
|
|
1676
|
+
const config = configMoveStruct;
|
|
1677
|
+
const { receivedSui } = package_MoonbagsPackage.Moonbags.sellReturns({
|
|
1678
|
+
amountIn: curveAmount,
|
|
1679
|
+
pool,
|
|
1680
|
+
config
|
|
1681
|
+
});
|
|
1682
|
+
if (frontendFee !== undefined) {
|
|
1683
|
+
return getAmountAfterFee(receivedSui, frontendFee);
|
|
1684
|
+
}
|
|
1685
|
+
return receivedSui;
|
|
1686
|
+
}
|
|
1687
|
+
MoonbagsCalculation.getSuiAmountAfterSell = getSuiAmountAfterSell;
|
|
1688
|
+
async function getUsedSuiForTx(params, suiClient) {
|
|
1689
|
+
let { suiAmount, frontendFee } = params;
|
|
1690
|
+
const configMoveStruct = await getMoveObjectContent(suiClient, constants_MoonbagsConstants.CONFIG_OBJECT_ID);
|
|
1691
|
+
const config = configMoveStruct;
|
|
1692
|
+
if (frontendFee !== undefined) {
|
|
1693
|
+
suiAmount = getAmountAfterFee(suiAmount, frontendFee);
|
|
1694
|
+
}
|
|
1695
|
+
return suiAmount * constants_MoonbagsConstants.FEE_DENOMINATOR / (constants_MoonbagsConstants.FEE_DENOMINATOR + BigInt(config.platform_fee));
|
|
1696
|
+
}
|
|
1697
|
+
MoonbagsCalculation.getUsedSuiForTx = getUsedSuiForTx;
|
|
1698
|
+
})(calculation_MoonbagsCalculation || (calculation_MoonbagsCalculation = {}));
|
|
1699
|
+
var calculation_MoonbagsCalculation;
|
|
1700
|
+
|
|
1701
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/moonbags/transaction.ts
|
|
1702
|
+
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
|
|
1706
|
+
|
|
1707
|
+
|
|
1708
|
+
|
|
1709
|
+
|
|
1710
|
+
(function(MoonbagsTransaction) {
|
|
1711
|
+
async function buildBuyTx(params, suiClient) {
|
|
1712
|
+
const { tx, coinOut } = await splitSuiCoinAfterFeeFromBuyTx(params, suiClient);
|
|
1713
|
+
tiny_invariant(coinOut, "Coin out is required");
|
|
1714
|
+
const usedSui = await calculation_MoonbagsCalculation.getUsedSuiForTx({
|
|
1715
|
+
suiAmount: BigInt(params.inputAmount),
|
|
1716
|
+
frontendFee: params.frontendFee
|
|
1717
|
+
}, suiClient);
|
|
1718
|
+
const [suiCoin, curveCoin] = tx.moveCall({
|
|
1719
|
+
target: `${constants_MoonbagsConstants.PACKAGE_ID}::moonbags::buy_exact_in_returns_with_lock`,
|
|
1720
|
+
typeArguments: [
|
|
1721
|
+
params.outCoinType
|
|
1722
|
+
],
|
|
1723
|
+
arguments: [
|
|
1724
|
+
tx.object(constants_MoonbagsConstants.CONFIG_OBJECT_ID),
|
|
1725
|
+
tx.object(constants_MoonbagsConstants.LOCK_CONFIG_OBJECT_ID),
|
|
1726
|
+
coinOut,
|
|
1727
|
+
tx.pure.u64(usedSui),
|
|
1728
|
+
tx.pure.u64(params.minAmountOut),
|
|
1729
|
+
tx.object(constants_MoonbagsConstants.BURN_MANAGER_OBJECT_ID),
|
|
1730
|
+
tx.object(constants_MoonbagsConstants.POOLS_OBJECT_ID),
|
|
1731
|
+
tx.object(constants_MoonbagsConstants.GLOBAL_CONFIG_OBJECT_ID),
|
|
1732
|
+
tx.object(SUI_METADATA_OBJECT_ID),
|
|
1733
|
+
tx.object(CLOCK_OBJECT_ID)
|
|
1734
|
+
]
|
|
1735
|
+
});
|
|
1736
|
+
bluefin_BluefinTx.transferOrDestroyZeroCoin(tx, SUI_FULL_TYPE, suiCoin, params.accountAddress);
|
|
1737
|
+
return {
|
|
1738
|
+
tx,
|
|
1739
|
+
coinOut: curveCoin
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
MoonbagsTransaction.buildBuyTx = buildBuyTx;
|
|
1743
|
+
async function buildSellTx(params, suiClient) {
|
|
1744
|
+
tiny_invariant(isSuiCoinType(params.outCoinType), "Output must be SUI");
|
|
1745
|
+
const { tx, coinData } = await getSplitCoinForTx({
|
|
1746
|
+
amount: params.inputAmount,
|
|
1747
|
+
coinType: params.inCoinType,
|
|
1748
|
+
inheritTx: params.extendTx?.tx,
|
|
1749
|
+
account: params.accountAddress,
|
|
1750
|
+
splits: [
|
|
1751
|
+
params.inputAmount
|
|
1752
|
+
]
|
|
1753
|
+
}, suiClient);
|
|
1754
|
+
const [inputCoin] = coinData;
|
|
1755
|
+
const [suiCoin, curveCoin] = tx.moveCall({
|
|
1756
|
+
target: `${constants_MoonbagsConstants.PACKAGE_ID}::moonbags::sell_returns`,
|
|
1757
|
+
typeArguments: [
|
|
1758
|
+
params.inCoinType
|
|
1759
|
+
],
|
|
1760
|
+
arguments: [
|
|
1761
|
+
tx.object(constants_MoonbagsConstants.CONFIG_OBJECT_ID),
|
|
1762
|
+
inputCoin,
|
|
1763
|
+
tx.pure.u64(params.minAmountOut),
|
|
1764
|
+
tx.object(CLOCK_OBJECT_ID)
|
|
1765
|
+
]
|
|
1766
|
+
});
|
|
1767
|
+
bluefin_BluefinTx.transferOrDestroyZeroCoin(tx, params.inCoinType, curveCoin, params.accountAddress);
|
|
1768
|
+
return await splitSuiCoinAfterFeeFromSellTx(tx, params, suiCoin);
|
|
1769
|
+
}
|
|
1770
|
+
MoonbagsTransaction.buildSellTx = buildSellTx;
|
|
1771
|
+
async function getBuyTransaction({ coinInAmount, coinInType, coinOutType, poolId, slippage, walletAddress, tradeFee }, suiClient) {
|
|
1772
|
+
tiny_invariant(isSuiCoinType(coinInType), "coinInType must be SUI for buy transaction");
|
|
1773
|
+
tiny_invariant(coinOutType !== coinInType, "coinOutType must be different from coinInType");
|
|
1774
|
+
tiny_invariant(slippage >= 0 && slippage < 1, "slippage must be between 0 (inclusive) and 1 (exclusive)");
|
|
1775
|
+
tiny_invariant(coinInAmount > 0, "coinInAmount must be greater than 0");
|
|
1776
|
+
const inputAmount = coinInAmount;
|
|
1777
|
+
const outputAmount = await calculation_MoonbagsCalculation.getCurveAmountAfterBuy({
|
|
1778
|
+
poolId: poolId,
|
|
1779
|
+
suiAmount: inputAmount,
|
|
1780
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined
|
|
1781
|
+
}, suiClient);
|
|
1782
|
+
const minAmountOut = BigInt(new bignumber(outputAmount.toString()).multipliedBy(1 - slippage).toFixed(0, 3));
|
|
1783
|
+
let { tx, coinOut } = await buildBuyTx({
|
|
1784
|
+
accountAddress: walletAddress,
|
|
1785
|
+
inCoinType: coinInType,
|
|
1786
|
+
outCoinType: coinOutType,
|
|
1787
|
+
inputAmount: inputAmount.toString(),
|
|
1788
|
+
minAmountOut: minAmountOut.toString(),
|
|
1789
|
+
poolId: poolId,
|
|
1790
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined,
|
|
1791
|
+
frontendFeeRecipient: tradeFee ? tradeFee.tradeFeeRecipientAddress : undefined,
|
|
1792
|
+
extendTx: undefined,
|
|
1793
|
+
isSponsored: false
|
|
1794
|
+
}, suiClient);
|
|
1795
|
+
tiny_invariant(coinOut, "Coin out is required");
|
|
1796
|
+
tx.transferObjects([
|
|
1797
|
+
coinOut
|
|
1798
|
+
], tx.pure.address(walletAddress));
|
|
1799
|
+
tx.setSender(walletAddress);
|
|
1800
|
+
const feeAmount = await getNeededGasFee(suiClient, tx, walletAddress, 0);
|
|
1801
|
+
tx = await addGasFee({
|
|
1802
|
+
inheritTx: tx,
|
|
1803
|
+
sender: walletAddress,
|
|
1804
|
+
feeAmount,
|
|
1805
|
+
suiInputAmount: inputAmount
|
|
1806
|
+
}, suiClient);
|
|
1807
|
+
return tx.build({
|
|
1808
|
+
client: suiClient
|
|
1809
|
+
});
|
|
1810
|
+
}
|
|
1811
|
+
MoonbagsTransaction.getBuyTransaction = getBuyTransaction;
|
|
1812
|
+
async function getSellTransaction({ coinInAmount, coinInType, coinOutType, poolId, slippage, walletAddress, tradeFee }, suiClient) {
|
|
1813
|
+
tiny_invariant(isSuiCoinType(coinOutType), "coinOutType must be SUI for sell transaction");
|
|
1814
|
+
tiny_invariant(coinOutType !== coinInType, "coinOutType must be different from coinInType");
|
|
1815
|
+
tiny_invariant(slippage >= 0 && slippage < 1, "slippage must be between 0 (inclusive) and 1 (exclusive)");
|
|
1816
|
+
tiny_invariant(coinInAmount > 0, "coinInAmount must be greater than 0");
|
|
1817
|
+
const inputAmount = coinInAmount;
|
|
1818
|
+
const outputAmount = await calculation_MoonbagsCalculation.getSuiAmountAfterSell({
|
|
1819
|
+
poolId: poolId,
|
|
1820
|
+
curveAmount: inputAmount,
|
|
1821
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined
|
|
1822
|
+
}, suiClient);
|
|
1823
|
+
const minAmountOut = BigInt(new bignumber(outputAmount.toString()).multipliedBy(1 - slippage).toFixed(0, 3));
|
|
1824
|
+
let { tx, coinOut } = await buildSellTx({
|
|
1825
|
+
accountAddress: walletAddress,
|
|
1826
|
+
inCoinType: coinInType,
|
|
1827
|
+
outCoinType: coinOutType,
|
|
1828
|
+
inputAmount: inputAmount.toString(),
|
|
1829
|
+
minAmountOut: minAmountOut.toString(),
|
|
1830
|
+
poolId: poolId,
|
|
1831
|
+
frontendFee: tradeFee ? tradeFee.tradeFeePercent : undefined,
|
|
1832
|
+
frontendFeeRecipient: tradeFee ? tradeFee.tradeFeeRecipientAddress : undefined,
|
|
1833
|
+
extendTx: undefined,
|
|
1834
|
+
isSponsored: false
|
|
1835
|
+
}, suiClient);
|
|
1836
|
+
tiny_invariant(coinOut, "Coin out is required");
|
|
1837
|
+
tx.transferObjects([
|
|
1838
|
+
coinOut
|
|
1839
|
+
], tx.pure.address(walletAddress));
|
|
1840
|
+
tx.setSender(walletAddress);
|
|
1841
|
+
const feeAmount = await getNeededGasFee(suiClient, tx, walletAddress, 0);
|
|
1842
|
+
tx = await addGasFee({
|
|
1843
|
+
inheritTx: tx,
|
|
1844
|
+
sender: walletAddress,
|
|
1845
|
+
feeAmount
|
|
1846
|
+
}, suiClient);
|
|
1847
|
+
return tx.build({
|
|
1848
|
+
client: suiClient
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
MoonbagsTransaction.getSellTransaction = getSellTransaction;
|
|
1852
|
+
})(transaction_MoonbagsTransaction || (transaction_MoonbagsTransaction = {}));
|
|
1853
|
+
var transaction_MoonbagsTransaction;
|
|
1854
|
+
|
|
1855
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/moonbags/index.ts
|
|
1856
|
+
|
|
1857
|
+
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
|
|
1861
|
+
;// CONCATENATED MODULE: ./src/bonding-curve/index.ts
|
|
1862
|
+
|
|
1863
|
+
|
|
1864
|
+
|
|
1865
|
+
|
|
1866
|
+
;// CONCATENATED MODULE: ./src/constant/index.ts
|
|
1867
|
+
|
|
1868
|
+
|
|
1869
|
+
|
|
1870
|
+
;// CONCATENATED MODULE: ./src/fee/index.ts
|
|
1871
|
+
|
|
1872
|
+
|
|
1873
|
+
;// CONCATENATED MODULE: ./src/libs/math/index.ts
|
|
1874
|
+
|
|
1875
|
+
|
|
1876
|
+
;// CONCATENATED MODULE: ./src/libs/sui-client-adapter.ts
|
|
1877
|
+
/**
|
|
1878
|
+
* Adapter to make SuiClient v1.38 compatible with libraries expecting v1.34
|
|
1879
|
+
* This works around TypeScript type incompatibilities between versions
|
|
1880
|
+
*/ function adaptSuiClient(client) {
|
|
1881
|
+
// Return the client with type assertion to bypass strict type checking
|
|
1882
|
+
// The underlying implementation is compatible, just the types differ
|
|
1883
|
+
return client;
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* Adapter to make Transaction v1.38 compatible with libraries expecting v1.34
|
|
1887
|
+
* This works around TypeScript type incompatibilities between versions
|
|
1888
|
+
*/ function adaptTransaction(transaction) {
|
|
1889
|
+
// Return the transaction with type assertion to bypass strict type checking
|
|
1890
|
+
// The underlying implementation is compatible, just the types differ
|
|
1891
|
+
return transaction;
|
|
1892
|
+
}
|
|
1893
|
+
/**
|
|
1894
|
+
* Alternative: Create a proxy that ensures compatibility
|
|
1895
|
+
*/ function createCompatibleSuiClient(client) {
|
|
1896
|
+
// You can add any necessary adaptations here if needed
|
|
1897
|
+
return new Proxy(client, {
|
|
1898
|
+
get (target, prop) {
|
|
1899
|
+
const value = target[prop];
|
|
1900
|
+
if (typeof value === "function") {
|
|
1901
|
+
return value.bind(target);
|
|
1902
|
+
}
|
|
1903
|
+
return value;
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
;// CONCATENATED MODULE: ./src/libs/index.ts
|
|
1909
|
+
|
|
1910
|
+
|
|
1911
|
+
|
|
1912
|
+
|
|
1913
|
+
|
|
1914
|
+
|
|
1915
|
+
|
|
1916
|
+
|
|
1917
|
+
;// CONCATENATED MODULE: ./src/modules/aggregator-module.ts
|
|
1918
|
+
|
|
1919
|
+
|
|
1920
|
+
/**
|
|
1921
|
+
* Main aggregator module that provides unified access to multiple DEX aggregators
|
|
1922
|
+
* Supports routing trades through Cetus, FlowX, Astros, Aftermath, and 7K Protocol
|
|
1923
|
+
*/ class AggregatorModule {
|
|
1924
|
+
/** Reference to the main Noodles SDK instance */ sdk;
|
|
1925
|
+
/** Astros/Navi Protocol aggregator instance */ _astrosAggregator;
|
|
1926
|
+
/** Aftermath Finance aggregator instance */ _aftermathAggregator;
|
|
1927
|
+
/** 7K Protocol aggregator instance */ _sevenkAggregator;
|
|
1928
|
+
/** Cetus Protocol aggregator instance */ _cetusAggregator;
|
|
1929
|
+
/** FlowX Finance aggregator instance */ _flowXAggregator;
|
|
1930
|
+
/**
|
|
1931
|
+
* Creates a new AggregatorModule instance with all supported aggregators
|
|
1932
|
+
* @param sdk - The main Noodles SDK instance containing configuration
|
|
1933
|
+
*/ constructor(sdk){
|
|
1934
|
+
this.sdk = sdk;
|
|
1935
|
+
this._astrosAggregator = new astros_AstrosAggregator({
|
|
1936
|
+
defaultTradeFee: sdk.options.tradeFee,
|
|
1937
|
+
astrosApiKey: sdk.options.astrosApiKey
|
|
1938
|
+
}, sdk.suiClient);
|
|
1939
|
+
this._aftermathAggregator = new aftermath_AftermathAggregator({
|
|
1940
|
+
defaultTradeFee: sdk.options.tradeFee,
|
|
1941
|
+
aftermathApiKey: sdk.options.aftermathApiKey,
|
|
1942
|
+
aftermathApiEndpoint: sdk.options.aftermathApiEndpoint
|
|
1943
|
+
}, sdk.suiClient);
|
|
1944
|
+
this._sevenkAggregator = new _7k_SevenKAggregator({
|
|
1945
|
+
defaultTradeFee: sdk.options.tradeFee,
|
|
1946
|
+
sevenKApiKey: sdk.options.sevenKApiKey
|
|
1947
|
+
}, sdk.suiClient);
|
|
1948
|
+
this._cetusAggregator = new cetus_CetusAggregator({
|
|
1949
|
+
defaultTradeFee: sdk.options.tradeFee,
|
|
1950
|
+
cetusApiKey: sdk.options.cetusApiKey,
|
|
1951
|
+
cetusApiEndpoint: sdk.options.cetusApiEndpoint,
|
|
1952
|
+
cetusPartnerId: sdk.options.cetusPartnerId
|
|
1953
|
+
}, sdk.suiClient);
|
|
1954
|
+
this._flowXAggregator = new flowx_FlowXAggregator({
|
|
1955
|
+
defaultTradeFee: sdk.options.tradeFee,
|
|
1956
|
+
flowxApiKey: sdk.options.flowxApiKey
|
|
1957
|
+
}, sdk.suiClient);
|
|
1958
|
+
}
|
|
1959
|
+
/** Gets the Astros/Navi Protocol aggregator instance */ get astrosAggregator() {
|
|
1960
|
+
return this._astrosAggregator;
|
|
1961
|
+
}
|
|
1962
|
+
/** Gets the Aftermath Finance aggregator instance */ get aftermathAggregator() {
|
|
1963
|
+
return this._aftermathAggregator;
|
|
1964
|
+
}
|
|
1965
|
+
/** Gets the 7K Protocol aggregator instance */ get sevenkAggregator() {
|
|
1966
|
+
return this._sevenkAggregator;
|
|
1967
|
+
}
|
|
1968
|
+
/** Gets the Cetus Protocol aggregator instance */ get cetusAggregator() {
|
|
1969
|
+
return this._cetusAggregator;
|
|
1970
|
+
}
|
|
1971
|
+
/** Gets the FlowX Finance aggregator instance */ get flowXAggregator() {
|
|
1972
|
+
return this._flowXAggregator;
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Finds the optimal trade route using the specified aggregator
|
|
1976
|
+
* @param aggregator - The aggregator to use for route finding
|
|
1977
|
+
* @param params - Trade route parameters including token types and amounts
|
|
1978
|
+
* @returns Promise resolving to route response with both standardized and raw data, or null if no route found
|
|
1979
|
+
*/ async getTradeRoute(aggregator, params) {
|
|
1980
|
+
let finalResponse;
|
|
1981
|
+
switch(aggregator){
|
|
1982
|
+
case common_SupportedAggregator.ASTROS:
|
|
1983
|
+
{
|
|
1984
|
+
const tradeRouteResponse = await this._astrosAggregator.getTradeRoute(params);
|
|
1985
|
+
if (!tradeRouteResponse) {
|
|
1986
|
+
return null;
|
|
1987
|
+
}
|
|
1988
|
+
const finalRoutes = astros_AstrosAggregator.toCommonTradeRoutes(tradeRouteResponse, params.coinInType, params.coinOutType);
|
|
1989
|
+
if (!finalRoutes) {
|
|
1990
|
+
return null;
|
|
1991
|
+
}
|
|
1992
|
+
let tradeFeePercent;
|
|
1993
|
+
if (params.tradeFee) {
|
|
1994
|
+
tradeFeePercent = params.tradeFee.tradeFeePercent;
|
|
1995
|
+
} else {
|
|
1996
|
+
tradeFeePercent = this.sdk.options.tradeFee.tradeFeePercent;
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Astros route amount_out does not consider the trade fee,
|
|
2000
|
+
* so we need to deduct the trade fee from the final amount_out
|
|
2001
|
+
*/ const finalAmountOut = BigInt(new bignumber(tradeRouteResponse.amount_out).multipliedBy(1 - tradeFeePercent).toFixed(0, 3));
|
|
2002
|
+
finalRoutes.amountOut = finalAmountOut;
|
|
2003
|
+
finalResponse = {
|
|
2004
|
+
route: finalRoutes,
|
|
2005
|
+
aggregatorRoute: tradeRouteResponse
|
|
2006
|
+
};
|
|
2007
|
+
break;
|
|
2008
|
+
}
|
|
2009
|
+
case common_SupportedAggregator.AFTERMATH:
|
|
2010
|
+
{
|
|
2011
|
+
const tradeRouteResponse = await this._aftermathAggregator.getTradeRoute(params);
|
|
2012
|
+
if (!tradeRouteResponse) {
|
|
2013
|
+
return null;
|
|
2014
|
+
}
|
|
2015
|
+
const finalRoutes = aftermath_AftermathAggregator.toCommonTradeRoutes(tradeRouteResponse);
|
|
2016
|
+
if (!finalRoutes) {
|
|
2017
|
+
return null;
|
|
2018
|
+
}
|
|
2019
|
+
finalResponse = {
|
|
2020
|
+
route: finalRoutes,
|
|
2021
|
+
aggregatorRoute: tradeRouteResponse
|
|
2022
|
+
};
|
|
2023
|
+
break;
|
|
2024
|
+
}
|
|
2025
|
+
case common_SupportedAggregator.SEVENK:
|
|
2026
|
+
{
|
|
2027
|
+
const tradeRouteResponse = await this._sevenkAggregator.getTradeRoute(params);
|
|
2028
|
+
if (!tradeRouteResponse) {
|
|
2029
|
+
return null;
|
|
2030
|
+
}
|
|
2031
|
+
const finalRoutes = _7k_SevenKAggregator.toCommonTradeRoutes(tradeRouteResponse);
|
|
2032
|
+
if (!finalRoutes) {
|
|
2033
|
+
return null;
|
|
2034
|
+
}
|
|
2035
|
+
finalResponse = {
|
|
2036
|
+
route: finalRoutes,
|
|
2037
|
+
aggregatorRoute: tradeRouteResponse
|
|
2038
|
+
};
|
|
2039
|
+
break;
|
|
2040
|
+
}
|
|
2041
|
+
case common_SupportedAggregator.CETUS:
|
|
2042
|
+
{
|
|
2043
|
+
const tradeRouteResponse = await this._cetusAggregator.getTradeRoute(params);
|
|
2044
|
+
if (!tradeRouteResponse) {
|
|
2045
|
+
return null;
|
|
2046
|
+
}
|
|
2047
|
+
const finalRoutes = cetus_CetusAggregator.toCommonTradeRoutes(tradeRouteResponse, params.coinInType, params.coinOutType);
|
|
2048
|
+
if (!finalRoutes) {
|
|
2049
|
+
return null;
|
|
2050
|
+
}
|
|
2051
|
+
finalResponse = {
|
|
2052
|
+
route: finalRoutes,
|
|
2053
|
+
aggregatorRoute: tradeRouteResponse
|
|
2054
|
+
};
|
|
2055
|
+
break;
|
|
2056
|
+
}
|
|
2057
|
+
case common_SupportedAggregator.FLOWX:
|
|
2058
|
+
{
|
|
2059
|
+
const tradeRouteResponse = await this._flowXAggregator.getTradeRoute(params);
|
|
2060
|
+
if (!tradeRouteResponse) {
|
|
2061
|
+
return null;
|
|
2062
|
+
}
|
|
2063
|
+
const finalRoutes = flowx_FlowXAggregator.toCommonTradeRoutes(tradeRouteResponse);
|
|
2064
|
+
if (!finalRoutes) {
|
|
2065
|
+
return null;
|
|
2066
|
+
}
|
|
2067
|
+
finalResponse = {
|
|
2068
|
+
route: finalRoutes,
|
|
2069
|
+
aggregatorRoute: tradeRouteResponse
|
|
2070
|
+
};
|
|
2071
|
+
break;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
return finalResponse;
|
|
2075
|
+
}
|
|
2076
|
+
/**
|
|
2077
|
+
* Builds a transaction from an existing trade route
|
|
2078
|
+
* @param aggregator - The aggregator that generated the route
|
|
2079
|
+
* @param params - Transaction parameters including wallet address, route, and slippage
|
|
2080
|
+
* @returns Promise resolving to built transaction bytes ready for signing and execution
|
|
2081
|
+
*/ async getTransactionByRoute(aggregator, params) {
|
|
2082
|
+
switch(aggregator){
|
|
2083
|
+
case common_SupportedAggregator.ASTROS:
|
|
2084
|
+
{
|
|
2085
|
+
return this._astrosAggregator.getTransaction({
|
|
2086
|
+
walletAddress: params.walletAddress,
|
|
2087
|
+
completeRoute: params.completeRoute,
|
|
2088
|
+
slippage: params.slippage,
|
|
2089
|
+
tradeFee: params.tradeFee
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
case common_SupportedAggregator.AFTERMATH:
|
|
2093
|
+
{
|
|
2094
|
+
return this._aftermathAggregator.getTransaction({
|
|
2095
|
+
walletAddress: params.walletAddress,
|
|
2096
|
+
completeRoute: params.completeRoute,
|
|
2097
|
+
slippage: params.slippage
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
case common_SupportedAggregator.SEVENK:
|
|
2101
|
+
{
|
|
2102
|
+
return this._sevenkAggregator.getTransaction({
|
|
2103
|
+
walletAddress: params.walletAddress,
|
|
2104
|
+
completeRoute: params.completeRoute,
|
|
2105
|
+
slippage: params.slippage,
|
|
2106
|
+
tradeFee: params.tradeFee
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
case common_SupportedAggregator.CETUS:
|
|
2110
|
+
{
|
|
2111
|
+
return this._cetusAggregator.getTransaction({
|
|
2112
|
+
walletAddress: params.walletAddress,
|
|
2113
|
+
completeRoute: params.completeRoute,
|
|
2114
|
+
slippage: params.slippage,
|
|
2115
|
+
tradeFee: params.tradeFee
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
case common_SupportedAggregator.FLOWX:
|
|
2119
|
+
{
|
|
2120
|
+
return this._flowXAggregator.getTransaction({
|
|
2121
|
+
walletAddress: params.walletAddress,
|
|
2122
|
+
completeRoute: params.completeRoute,
|
|
2123
|
+
slippage: params.slippage,
|
|
2124
|
+
tradeFee: params.tradeFee
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
/**
|
|
2130
|
+
* Combines route finding and transaction building into a single operation
|
|
2131
|
+
* This is a convenience method that calls getTradeRoute followed by getTransactionByRoute
|
|
2132
|
+
* @param aggregator - The aggregator to use for both route finding and transaction building
|
|
2133
|
+
* @param params - Combined parameters including trade details, wallet address, and slippage
|
|
2134
|
+
* @returns Promise resolving to complete response with route info and built transaction, or null if no route found
|
|
2135
|
+
*/ async getTradeTransaction(aggregator, params) {
|
|
2136
|
+
const routeResponse = await this.getTradeRoute(aggregator, {
|
|
2137
|
+
coinInAmount: params.coinInAmount,
|
|
2138
|
+
coinInType: params.coinInType,
|
|
2139
|
+
coinOutType: params.coinOutType,
|
|
2140
|
+
tradeFee: params.tradeFee
|
|
2141
|
+
});
|
|
2142
|
+
if (!routeResponse) {
|
|
2143
|
+
return null;
|
|
2144
|
+
}
|
|
2145
|
+
const transaction = await this.getTransactionByRoute(aggregator, {
|
|
2146
|
+
walletAddress: params.walletAddress,
|
|
2147
|
+
completeRoute: routeResponse.aggregatorRoute,
|
|
2148
|
+
slippage: params.slippage,
|
|
2149
|
+
tradeFee: params.tradeFee
|
|
2150
|
+
});
|
|
2151
|
+
return {
|
|
2152
|
+
route: routeResponse.route,
|
|
2153
|
+
aggregatorRoute: routeResponse.aggregatorRoute,
|
|
2154
|
+
transaction
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
/**
|
|
2158
|
+
* Finds the best rate across all aggregators and returns the optimal trade transaction
|
|
2159
|
+
* This method queries all available aggregators and selects the one with the best output amount
|
|
2160
|
+
* @param params - Combined parameters including trade details, wallet address, and slippage
|
|
2161
|
+
* @returns Promise resolving to complete response with route info and built transaction from the best aggregator, or null if no routes found
|
|
2162
|
+
*/ async getTradeTransactionWithBestRate(params) {
|
|
2163
|
+
const aggregators = Object.keys(common_SupportedAggregator);
|
|
2164
|
+
const tradeRouteResponses = await Promise.all(aggregators.map(async (aggregator)=>{
|
|
2165
|
+
try {
|
|
2166
|
+
return await this.getTradeRoute(aggregator, params);
|
|
2167
|
+
} catch {
|
|
2168
|
+
return null;
|
|
2169
|
+
}
|
|
2170
|
+
}));
|
|
2171
|
+
let bestResponse = null;
|
|
2172
|
+
let chosenAggregator = null;
|
|
2173
|
+
for(let i = 0; i < tradeRouteResponses.length; i++){
|
|
2174
|
+
const tradeRouteResponse = tradeRouteResponses[i];
|
|
2175
|
+
const aggregator = aggregators[i];
|
|
2176
|
+
if (!tradeRouteResponse) {
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
if (!bestResponse) {
|
|
2180
|
+
bestResponse = tradeRouteResponse;
|
|
2181
|
+
chosenAggregator = aggregator;
|
|
2182
|
+
continue;
|
|
2183
|
+
}
|
|
2184
|
+
if (tradeRouteResponse.route.amountOut > bestResponse.route.amountOut) {
|
|
2185
|
+
bestResponse = tradeRouteResponse;
|
|
2186
|
+
chosenAggregator = aggregator;
|
|
2187
|
+
continue;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
if (!bestResponse || !chosenAggregator) {
|
|
2191
|
+
return null;
|
|
2192
|
+
}
|
|
2193
|
+
const transaction = await this.getTransactionByRoute(chosenAggregator, {
|
|
2194
|
+
walletAddress: params.walletAddress,
|
|
2195
|
+
completeRoute: bestResponse.aggregatorRoute,
|
|
2196
|
+
slippage: params.slippage,
|
|
2197
|
+
tradeFee: params.tradeFee
|
|
2198
|
+
});
|
|
2199
|
+
return {
|
|
2200
|
+
route: bestResponse.route,
|
|
2201
|
+
aggregatorRoute: bestResponse.aggregatorRoute,
|
|
2202
|
+
transaction
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Gets the expected output amount for a trade using the specified aggregator
|
|
2207
|
+
* This is a lightweight method that only fetches the route and returns the output amount
|
|
2208
|
+
* without building a transaction
|
|
2209
|
+
*
|
|
2210
|
+
* @param aggregator - The aggregator to use for calculating output amount
|
|
2211
|
+
* @param params - Trade route parameters including token types and input amount
|
|
2212
|
+
* @returns Promise resolving to the expected output amount in smallest unit, or null if no route found
|
|
2213
|
+
*/ async getAmountOut(aggregator, params) {
|
|
2214
|
+
const tradeRouteResult = await this.getTradeRoute(aggregator, params);
|
|
2215
|
+
if (!tradeRouteResult) {
|
|
2216
|
+
return null;
|
|
2217
|
+
}
|
|
2218
|
+
return tradeRouteResult.route.amountOut;
|
|
2219
|
+
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Finds the best output amount across all aggregators without building a transaction
|
|
2222
|
+
* This method queries all available aggregators in parallel and returns the aggregator
|
|
2223
|
+
* that provides the highest output amount along with that amount
|
|
2224
|
+
*
|
|
2225
|
+
* @param params - Trade route parameters including token types and input amount
|
|
2226
|
+
* @returns Promise resolving to an object containing the best output amount and the aggregator that provided it, or null if no routes found
|
|
2227
|
+
*/ async getBestAmountOut(params) {
|
|
2228
|
+
const aggregators = Object.keys(common_SupportedAggregator);
|
|
2229
|
+
let bestAmountOut = null;
|
|
2230
|
+
let bestAggregator = null;
|
|
2231
|
+
for (const aggregator of aggregators){
|
|
2232
|
+
const amountOut = await this.getAmountOut(aggregator, params);
|
|
2233
|
+
if (amountOut === null) {
|
|
2234
|
+
continue;
|
|
2235
|
+
}
|
|
2236
|
+
if (bestAmountOut === null || amountOut > bestAmountOut) {
|
|
2237
|
+
bestAmountOut = amountOut;
|
|
2238
|
+
bestAggregator = aggregator;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
if (bestAmountOut === null || bestAggregator === null) {
|
|
2242
|
+
return null;
|
|
2243
|
+
}
|
|
2244
|
+
return {
|
|
2245
|
+
amountOut: bestAmountOut,
|
|
2246
|
+
aggregator: bestAggregator
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
;// CONCATENATED MODULE: ./src/modules/boosting-module.ts
|
|
2252
|
+
|
|
2253
|
+
|
|
2254
|
+
|
|
2255
|
+
|
|
2256
|
+
/** Sui package ID for the boosting protocol */ const BOOSTING_PACKAGE_ID = "0x25fa0eb553dd69fa6a8028f73a38f1df7f289fa88a58ed3d7dc5a5360155bb19";
|
|
2257
|
+
/** Configuration object ID for boosting settings */ const CONFIG_ID = "0x8b1a8ac6e34688cd8f8f8e5fefa9d5fb9e1ff74d2f132f8e208ae5ac9cc530bb";
|
|
2258
|
+
/** Admin capability object ID for privileged operations */ const ADMIN_CAP_ID = "0x13d101f44a0710a5475bec5f492a87b80e03d92d1cf540f26096f65850b23d26";
|
|
2259
|
+
/**
|
|
2260
|
+
* Module for managing boosting functionality in the Noodles SDK.
|
|
2261
|
+
*
|
|
2262
|
+
* This module provides methods for:
|
|
2263
|
+
* - Paying boosting fees for different tiers
|
|
2264
|
+
* - Managing boosting tiers (admin functions)
|
|
2265
|
+
* - Retrieving boosting configuration
|
|
2266
|
+
* - Updating fee receiver settings
|
|
2267
|
+
*/ class BoostingModule {
|
|
2268
|
+
/** Reference to the main SDK instance */ sdk;
|
|
2269
|
+
/**
|
|
2270
|
+
* Creates a new BoostingModule instance.
|
|
2271
|
+
*
|
|
2272
|
+
* @param sdk - The main Noodles Pay SDK instance
|
|
2273
|
+
*/ constructor(sdk){
|
|
2274
|
+
this.sdk = sdk;
|
|
2275
|
+
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Retrieves the current boosting configuration from the blockchain.
|
|
2278
|
+
*
|
|
2279
|
+
* @returns Promise resolving to the current boosting configuration
|
|
2280
|
+
* @throws Error if config object is not found or invalid
|
|
2281
|
+
*/ async getConfig() {
|
|
2282
|
+
const configObject = await this.sdk.suiClient.getObject({
|
|
2283
|
+
id: CONFIG_ID,
|
|
2284
|
+
options: {
|
|
2285
|
+
showContent: true
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
tiny_invariant(configObject.data?.content, "Config object not found or has no content");
|
|
2289
|
+
tiny_invariant(configObject.data?.content.dataType === "moveObject", "Config object is not a Move object");
|
|
2290
|
+
const objectFields = configObject.data.content.fields;
|
|
2291
|
+
const id = objectFields.id.id;
|
|
2292
|
+
const feeReceiver = objectFields.fee_receiver;
|
|
2293
|
+
const tiers = objectFields.tiers.fields.contents;
|
|
2294
|
+
// Parse tier information from blockchain data
|
|
2295
|
+
const tierMap = {};
|
|
2296
|
+
for (const tier of tiers){
|
|
2297
|
+
const key = tier.fields.key;
|
|
2298
|
+
const duration = tier.fields.value.fields.duration;
|
|
2299
|
+
const amount = tier.fields.value.fields.amount;
|
|
2300
|
+
const point = tier.fields.value.fields.point;
|
|
2301
|
+
const originalAmount = tier.fields.value.fields.original_amount;
|
|
2302
|
+
tierMap[key] = {
|
|
2303
|
+
duration: BigInt(duration),
|
|
2304
|
+
amount: BigInt(amount),
|
|
2305
|
+
point: BigInt(point),
|
|
2306
|
+
originalAmount: BigInt(originalAmount)
|
|
2307
|
+
};
|
|
2308
|
+
}
|
|
2309
|
+
return {
|
|
2310
|
+
id,
|
|
2311
|
+
receiverAddress: feeReceiver,
|
|
2312
|
+
tiers: tierMap
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Builds a transaction for paying boosting fees for a specific tier.
|
|
2317
|
+
* The payment amount is determined by the tier configuration.
|
|
2318
|
+
*
|
|
2319
|
+
* @param request - Payment request parameters
|
|
2320
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2321
|
+
* @throws Error if tier ID is invalid
|
|
2322
|
+
*/ async buildPayBoostingTx({ walletAddress, tierId, boostingCoinType, currentTx }) {
|
|
2323
|
+
const configObj = await this.getConfig();
|
|
2324
|
+
tiny_invariant(tierId in configObj.tiers, "Invalid tier ID");
|
|
2325
|
+
const tier = configObj.tiers[tierId];
|
|
2326
|
+
const paymentAmount = tier.amount;
|
|
2327
|
+
const tx = currentTx || new Transaction();
|
|
2328
|
+
const paymentCoin = tx.splitCoins(tx.gas, [
|
|
2329
|
+
tx.pure.u64(paymentAmount)
|
|
2330
|
+
]);
|
|
2331
|
+
tx.moveCall({
|
|
2332
|
+
target: `${BOOSTING_PACKAGE_ID}::boosting::pay`,
|
|
2333
|
+
typeArguments: [
|
|
2334
|
+
normalizeStructTag(boostingCoinType)
|
|
2335
|
+
],
|
|
2336
|
+
arguments: [
|
|
2337
|
+
tx.object(CONFIG_ID),
|
|
2338
|
+
tx.pure.u64(tierId),
|
|
2339
|
+
paymentCoin
|
|
2340
|
+
]
|
|
2341
|
+
});
|
|
2342
|
+
tx.setSender(walletAddress);
|
|
2343
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, walletAddress, 0);
|
|
2344
|
+
return addGasFee({
|
|
2345
|
+
inheritTx: tx,
|
|
2346
|
+
sender: walletAddress,
|
|
2347
|
+
feeAmount: gasAmount
|
|
2348
|
+
}, this.sdk.suiClient);
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Builds a transaction for adding a new boosting tier.
|
|
2352
|
+
*
|
|
2353
|
+
* **Requires admin capability.**
|
|
2354
|
+
*
|
|
2355
|
+
* @param request - Add tier request parameters
|
|
2356
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2357
|
+
*/ async buildAddTierTx({ adminAddress, tierId, duration, point, originalAmount, amount, currentTx }) {
|
|
2358
|
+
const tx = currentTx || new Transaction();
|
|
2359
|
+
tx.moveCall({
|
|
2360
|
+
target: `${BOOSTING_PACKAGE_ID}::config::add_tier`,
|
|
2361
|
+
typeArguments: [],
|
|
2362
|
+
arguments: [
|
|
2363
|
+
tx.object(CONFIG_ID),
|
|
2364
|
+
tx.object(ADMIN_CAP_ID),
|
|
2365
|
+
tx.pure.u64(tierId),
|
|
2366
|
+
tx.pure.u64(point),
|
|
2367
|
+
tx.pure.u64(duration),
|
|
2368
|
+
tx.pure.u64(originalAmount),
|
|
2369
|
+
tx.pure.u64(amount)
|
|
2370
|
+
]
|
|
2371
|
+
});
|
|
2372
|
+
tx.setSender(adminAddress);
|
|
2373
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2374
|
+
return addGasFee({
|
|
2375
|
+
inheritTx: tx,
|
|
2376
|
+
sender: adminAddress,
|
|
2377
|
+
feeAmount: gasAmount
|
|
2378
|
+
}, this.sdk.suiClient);
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Builds a transaction for updating an existing boosting tier.
|
|
2382
|
+
*
|
|
2383
|
+
* **Requires admin capability.**
|
|
2384
|
+
*
|
|
2385
|
+
* @param request - Update tier request parameters
|
|
2386
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2387
|
+
*/ async buildUpdateTierTx({ adminAddress, tierId, duration, amount, originalAmount, point, currentTx }) {
|
|
2388
|
+
const tx = currentTx || new Transaction();
|
|
2389
|
+
tx.moveCall({
|
|
2390
|
+
target: `${BOOSTING_PACKAGE_ID}::config::update_tier`,
|
|
2391
|
+
typeArguments: [],
|
|
2392
|
+
arguments: [
|
|
2393
|
+
tx.object(CONFIG_ID),
|
|
2394
|
+
tx.object(ADMIN_CAP_ID),
|
|
2395
|
+
tx.pure.u64(tierId),
|
|
2396
|
+
tx.pure.u64(duration),
|
|
2397
|
+
tx.pure.u64(amount),
|
|
2398
|
+
tx.pure.u64(point),
|
|
2399
|
+
tx.pure.u64(originalAmount)
|
|
2400
|
+
]
|
|
2401
|
+
});
|
|
2402
|
+
tx.setSender(adminAddress);
|
|
2403
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2404
|
+
return addGasFee({
|
|
2405
|
+
inheritTx: tx,
|
|
2406
|
+
sender: adminAddress,
|
|
2407
|
+
feeAmount: gasAmount
|
|
2408
|
+
}, this.sdk.suiClient);
|
|
2409
|
+
}
|
|
2410
|
+
/**
|
|
2411
|
+
* Builds a transaction for removing a boosting tier.
|
|
2412
|
+
*
|
|
2413
|
+
* **Requires admin capability.**
|
|
2414
|
+
*
|
|
2415
|
+
* @param request - Remove tier request parameters
|
|
2416
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2417
|
+
*/ async buildRemoveTierTx({ adminAddress, tierId, currentTx }) {
|
|
2418
|
+
const tx = currentTx || new Transaction();
|
|
2419
|
+
tx.moveCall({
|
|
2420
|
+
target: `${BOOSTING_PACKAGE_ID}::config::remove_tier`,
|
|
2421
|
+
typeArguments: [],
|
|
2422
|
+
arguments: [
|
|
2423
|
+
tx.object(CONFIG_ID),
|
|
2424
|
+
tx.object(ADMIN_CAP_ID),
|
|
2425
|
+
tx.pure.u64(tierId)
|
|
2426
|
+
]
|
|
2427
|
+
});
|
|
2428
|
+
tx.setSender(adminAddress);
|
|
2429
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2430
|
+
return addGasFee({
|
|
2431
|
+
inheritTx: tx,
|
|
2432
|
+
sender: adminAddress,
|
|
2433
|
+
feeAmount: gasAmount
|
|
2434
|
+
}, this.sdk.suiClient);
|
|
2435
|
+
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Builds a transaction for updating the fee receiver address.
|
|
2438
|
+
*
|
|
2439
|
+
* **Requires admin capability.**
|
|
2440
|
+
*
|
|
2441
|
+
* @param request - Update fee receiver request parameters
|
|
2442
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2443
|
+
*/ async buildUpdateFeeReceiver({ adminAddress, newReceiverAddress, currentTx }) {
|
|
2444
|
+
const tx = currentTx || new Transaction();
|
|
2445
|
+
tx.moveCall({
|
|
2446
|
+
target: `${BOOSTING_PACKAGE_ID}::config::update_fee_receiver`,
|
|
2447
|
+
typeArguments: [],
|
|
2448
|
+
arguments: [
|
|
2449
|
+
tx.object(CONFIG_ID),
|
|
2450
|
+
tx.object(ADMIN_CAP_ID),
|
|
2451
|
+
tx.pure.address(newReceiverAddress)
|
|
2452
|
+
]
|
|
2453
|
+
});
|
|
2454
|
+
tx.setSender(adminAddress);
|
|
2455
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2456
|
+
return addGasFee({
|
|
2457
|
+
inheritTx: tx,
|
|
2458
|
+
sender: adminAddress,
|
|
2459
|
+
feeAmount: gasAmount
|
|
2460
|
+
}, this.sdk.suiClient);
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Builds a transaction for paying boosting fees with admin privileges.
|
|
2464
|
+
* Allows specifying a custom payment amount instead of using the tier's default amount.
|
|
2465
|
+
*
|
|
2466
|
+
* **Requires admin capability.**
|
|
2467
|
+
*
|
|
2468
|
+
* @param request - Admin payment request parameters
|
|
2469
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2470
|
+
*/ async buildPayBoostingWithAdminTx({ walletAddress, tierId, customAmount, boostingCoinType, currentTx }) {
|
|
2471
|
+
const tx = currentTx || new Transaction();
|
|
2472
|
+
const paymentCoin = tx.splitCoins(tx.gas, [
|
|
2473
|
+
tx.pure.u64(customAmount)
|
|
2474
|
+
]);
|
|
2475
|
+
tx.moveCall({
|
|
2476
|
+
target: `${BOOSTING_PACKAGE_ID}::boosting::pay_with_admin`,
|
|
2477
|
+
typeArguments: [
|
|
2478
|
+
normalizeStructTag(boostingCoinType)
|
|
2479
|
+
],
|
|
2480
|
+
arguments: [
|
|
2481
|
+
tx.object(ADMIN_CAP_ID),
|
|
2482
|
+
tx.object(CONFIG_ID),
|
|
2483
|
+
tx.pure.u64(tierId),
|
|
2484
|
+
tx.pure.u64(customAmount),
|
|
2485
|
+
paymentCoin
|
|
2486
|
+
]
|
|
2487
|
+
});
|
|
2488
|
+
tx.setSender(walletAddress);
|
|
2489
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, walletAddress, 0);
|
|
2490
|
+
return addGasFee({
|
|
2491
|
+
inheritTx: tx,
|
|
2492
|
+
sender: walletAddress,
|
|
2493
|
+
feeAmount: gasAmount
|
|
2494
|
+
}, this.sdk.suiClient);
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
;// CONCATENATED MODULE: ./src/modules/curve-module.ts
|
|
2499
|
+
|
|
2500
|
+
|
|
2501
|
+
|
|
2502
|
+
class CurveModule {
|
|
2503
|
+
sdk;
|
|
2504
|
+
constructor(sdk){
|
|
2505
|
+
this.sdk = sdk;
|
|
2506
|
+
}
|
|
2507
|
+
async getEstimatedAmountOut(platform, params) {
|
|
2508
|
+
const { coinInType, coinOutType } = params;
|
|
2509
|
+
tiny_invariant(coinInType !== coinOutType, "coinInType and coinOutType must be different");
|
|
2510
|
+
tiny_invariant(isSuiCoinType(coinInType) || isSuiCoinType(coinOutType), "One of coinInType or coinOutType must be SUI");
|
|
2511
|
+
const isBuy = isSuiCoinType(coinInType);
|
|
2512
|
+
switch(platform){
|
|
2513
|
+
case types_SupportedBondingCurve.MOONBAGS:
|
|
2514
|
+
{
|
|
2515
|
+
if (isBuy) {
|
|
2516
|
+
return await calculation_MoonbagsCalculation.getCurveAmountAfterBuy({
|
|
2517
|
+
poolId: params.poolId,
|
|
2518
|
+
suiAmount: params.coinInAmount,
|
|
2519
|
+
frontendFee: params.tradeFee ? params.tradeFee.tradeFeePercent : undefined
|
|
2520
|
+
}, this.sdk.suiClient);
|
|
2521
|
+
} else {
|
|
2522
|
+
return await calculation_MoonbagsCalculation.getSuiAmountAfterSell({
|
|
2523
|
+
poolId: params.poolId,
|
|
2524
|
+
curveAmount: params.coinInAmount,
|
|
2525
|
+
frontendFee: params.tradeFee ? params.tradeFee.tradeFeePercent : undefined
|
|
2526
|
+
}, this.sdk.suiClient);
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
case types_SupportedBondingCurve.BLAST_FUN:
|
|
2530
|
+
{
|
|
2531
|
+
if (isBuy) {
|
|
2532
|
+
return await sdk_calculation_BlastFunSDKCalculation.getCurveAmountAfterBuy({
|
|
2533
|
+
poolId: params.poolId,
|
|
2534
|
+
suiAmount: params.coinInAmount,
|
|
2535
|
+
frontendFee: params.tradeFee ? params.tradeFee.tradeFeePercent : undefined
|
|
2536
|
+
});
|
|
2537
|
+
} else {
|
|
2538
|
+
return await sdk_calculation_BlastFunSDKCalculation.getSuiAmountAfterSell({
|
|
2539
|
+
poolId: params.poolId,
|
|
2540
|
+
curveAmount: params.coinInAmount,
|
|
2541
|
+
frontendFee: params.tradeFee ? params.tradeFee.tradeFeePercent : undefined
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
default:
|
|
2546
|
+
throw new Error(`Unsupported bonding curve platform: ${platform}`);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
async getTradeTransaction(platform, params) {
|
|
2550
|
+
const { coinInType, coinOutType } = params;
|
|
2551
|
+
tiny_invariant(coinInType !== coinOutType, "coinInType and coinOutType must be different");
|
|
2552
|
+
tiny_invariant(isSuiCoinType(coinInType) || isSuiCoinType(coinOutType), "One of coinInType or coinOutType must be SUI");
|
|
2553
|
+
const isBuy = isSuiCoinType(coinInType);
|
|
2554
|
+
let tx;
|
|
2555
|
+
switch(platform){
|
|
2556
|
+
case types_SupportedBondingCurve.MOONBAGS:
|
|
2557
|
+
{
|
|
2558
|
+
if (isBuy) {
|
|
2559
|
+
tx = await transaction_MoonbagsTransaction.getBuyTransaction(params, this.sdk.suiClient);
|
|
2560
|
+
} else {
|
|
2561
|
+
tx = await transaction_MoonbagsTransaction.getSellTransaction(params, this.sdk.suiClient);
|
|
2562
|
+
}
|
|
2563
|
+
break;
|
|
2564
|
+
}
|
|
2565
|
+
case types_SupportedBondingCurve.BLAST_FUN:
|
|
2566
|
+
{
|
|
2567
|
+
if (isBuy) {
|
|
2568
|
+
tx = await sdk_transaction_BlastFunSDKTransaction.getBuyTransaction(params, this.sdk.suiClient);
|
|
2569
|
+
} else {
|
|
2570
|
+
tx = await sdk_transaction_BlastFunSDKTransaction.getSellTransaction(params, this.sdk.suiClient);
|
|
2571
|
+
}
|
|
2572
|
+
break;
|
|
2573
|
+
}
|
|
2574
|
+
default:
|
|
2575
|
+
throw new Error(`Unsupported bonding curve platform: ${platform}`);
|
|
2576
|
+
}
|
|
2577
|
+
return tx;
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
;// CONCATENATED MODULE: ./src/modules/subscription-module.ts
|
|
2582
|
+
|
|
2583
|
+
|
|
2584
|
+
|
|
2585
|
+
/** Sui package ID for the subscription protocol */ const SUBSCRIPTION_PACKAGE_ID = "0x5dd4286ec234c117bb9577d4eaed1885b70d73ab1d3dab2794d0ab9a2c06c4a1";
|
|
2586
|
+
/** Configuration object ID for subscription settings */ const SUBSCRIPTION_CONFIG_ID = "0x095b941beff22213fe8ccb223e4d1c5b4ede4dcd7f82ca4bb18c9a45fd3d6e20";
|
|
2587
|
+
/** Admin capability object ID for privileged operations */ const SUBSCRIPTION_ADMIN_CAP_ID = "0xdc27fe8187131b7fc095fccd213b79f72312793152a2483d1f67199c390e256d";
|
|
2588
|
+
/** Payment coin type on SUI */ const PAYMENT_COIN_TYPE = "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC";
|
|
2589
|
+
/**
|
|
2590
|
+
* Module for managing subscription functionality in the Noodles SDK.
|
|
2591
|
+
*
|
|
2592
|
+
* This module provides methods for:
|
|
2593
|
+
* - Subscribing to plans
|
|
2594
|
+
* - Upgrading plans (immediate or next billing cycle)
|
|
2595
|
+
* - Managing subscription plans (admin functions)
|
|
2596
|
+
* - Retrieving subscription configuration
|
|
2597
|
+
* - Updating fee receiver wallet and pause settings
|
|
2598
|
+
*/ class SubscriptionModule {
|
|
2599
|
+
/** Reference to the main SDK instance */ sdk;
|
|
2600
|
+
/**
|
|
2601
|
+
* Creates a new SubscriptionModule instance.
|
|
2602
|
+
*
|
|
2603
|
+
* @param sdk - The main Noodles Pay SDK instance
|
|
2604
|
+
*/ constructor(sdk){
|
|
2605
|
+
this.sdk = sdk;
|
|
2606
|
+
}
|
|
2607
|
+
/**
|
|
2608
|
+
* Retrieves the current subscription configuration from the blockchain.
|
|
2609
|
+
*
|
|
2610
|
+
* @returns Promise resolving to the current subscription configuration
|
|
2611
|
+
* @throws Error if config object is not found or invalid
|
|
2612
|
+
*/ async getConfig() {
|
|
2613
|
+
const configObject = await this.sdk.suiClient.getObject({
|
|
2614
|
+
id: SUBSCRIPTION_CONFIG_ID,
|
|
2615
|
+
options: {
|
|
2616
|
+
showContent: true
|
|
2617
|
+
}
|
|
2618
|
+
});
|
|
2619
|
+
tiny_invariant(configObject.data, "Config object not found");
|
|
2620
|
+
tiny_invariant(configObject.data.content, "Config object has no content");
|
|
2621
|
+
tiny_invariant(configObject.data?.content.dataType === "moveObject", "Config object is not a Move object");
|
|
2622
|
+
const objectFields = configObject.data.content.fields;
|
|
2623
|
+
const id = objectFields.id.id;
|
|
2624
|
+
const feeReceiverWallet = objectFields.fee_receiver;
|
|
2625
|
+
const paused = objectFields.paused;
|
|
2626
|
+
const acceptedPaymentType = objectFields.accepted_payment_type;
|
|
2627
|
+
const plans = objectFields.plans.fields.contents;
|
|
2628
|
+
// Parse plan information from blockchain data
|
|
2629
|
+
const planMap = {};
|
|
2630
|
+
for (const plan of plans){
|
|
2631
|
+
const key = plan.fields.key;
|
|
2632
|
+
const planId = plan.fields.value.fields.id;
|
|
2633
|
+
const price = plan.fields.value.fields.price;
|
|
2634
|
+
const monthInterval = plan.fields.value.fields.month_interval;
|
|
2635
|
+
const planType = plan.fields.value.fields.ptype;
|
|
2636
|
+
planMap[key] = {
|
|
2637
|
+
id: BigInt(planId),
|
|
2638
|
+
price: BigInt(price),
|
|
2639
|
+
monthInterval: monthInterval,
|
|
2640
|
+
planType: planType
|
|
2641
|
+
};
|
|
2642
|
+
}
|
|
2643
|
+
return {
|
|
2644
|
+
id,
|
|
2645
|
+
plans: planMap,
|
|
2646
|
+
feeReceiverWallet: feeReceiverWallet,
|
|
2647
|
+
paused,
|
|
2648
|
+
acceptedPaymentType
|
|
2649
|
+
};
|
|
2650
|
+
}
|
|
2651
|
+
/**
|
|
2652
|
+
* Builds a transaction for subscribing to a plan.
|
|
2653
|
+
* The payment amount is determined by the plan configuration.
|
|
2654
|
+
*
|
|
2655
|
+
* @param request - Subscription request parameters
|
|
2656
|
+
* @reference order_id generated from your backend to identify the purchase
|
|
2657
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2658
|
+
* @throws Error if plan ID is invalid or contract is paused
|
|
2659
|
+
*/ async buildSubscribeCyclePlanTx({ walletAddress, planId, reference, paymentCoinType = PAYMENT_COIN_TYPE, currentTx }) {
|
|
2660
|
+
const configObj = await this.getConfig();
|
|
2661
|
+
tiny_invariant(!configObj.paused, "Contract is paused");
|
|
2662
|
+
tiny_invariant(planId in configObj.plans, "Invalid plan ID");
|
|
2663
|
+
const plan = configObj.plans[planId];
|
|
2664
|
+
const paymentAmount = plan.price;
|
|
2665
|
+
// Get USDC coins from user's wallet
|
|
2666
|
+
const { tx: txWithCoin, coinData } = await getSplitCoinForTx({
|
|
2667
|
+
account: walletAddress,
|
|
2668
|
+
amount: paymentAmount.toString(),
|
|
2669
|
+
splits: [
|
|
2670
|
+
paymentAmount.toString()
|
|
2671
|
+
],
|
|
2672
|
+
coinType: paymentCoinType,
|
|
2673
|
+
inheritTx: currentTx
|
|
2674
|
+
}, this.sdk.suiClient);
|
|
2675
|
+
txWithCoin.moveCall({
|
|
2676
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::subscription::subscribe_cycle_plan`,
|
|
2677
|
+
typeArguments: [
|
|
2678
|
+
paymentCoinType
|
|
2679
|
+
],
|
|
2680
|
+
arguments: [
|
|
2681
|
+
txWithCoin.object(SUBSCRIPTION_CONFIG_ID),
|
|
2682
|
+
txWithCoin.pure.u64(planId),
|
|
2683
|
+
txWithCoin.pure.string(reference),
|
|
2684
|
+
coinData
|
|
2685
|
+
]
|
|
2686
|
+
});
|
|
2687
|
+
txWithCoin.setSender(walletAddress);
|
|
2688
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, txWithCoin, walletAddress, 0);
|
|
2689
|
+
return addGasFee({
|
|
2690
|
+
inheritTx: txWithCoin,
|
|
2691
|
+
sender: walletAddress,
|
|
2692
|
+
feeAmount: gasAmount
|
|
2693
|
+
}, this.sdk.suiClient);
|
|
2694
|
+
}
|
|
2695
|
+
/**
|
|
2696
|
+
* Builds a transaction for buying additional compute units (CU) for CUAddOn plans.
|
|
2697
|
+
*
|
|
2698
|
+
* @param request - Buy more CU request parameters
|
|
2699
|
+
* @reference order_id generated from your backend to identify the purchase
|
|
2700
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2701
|
+
* @throws Error if plan ID is invalid or contract is paused
|
|
2702
|
+
*/ async buildBuyMoreCUPlanTx({ walletAddress, planId, reference, paidAmount, paymentCoinType = PAYMENT_COIN_TYPE, currentTx }) {
|
|
2703
|
+
const configObj = await this.getConfig();
|
|
2704
|
+
tiny_invariant(!configObj.paused, "Contract is paused");
|
|
2705
|
+
tiny_invariant(planId in configObj.plans, "Invalid plan ID");
|
|
2706
|
+
// Get USDC coins from user's wallet
|
|
2707
|
+
const { tx: txWithCoin, coinData } = await getSplitCoinForTx({
|
|
2708
|
+
account: walletAddress,
|
|
2709
|
+
amount: paidAmount.toString(),
|
|
2710
|
+
splits: [
|
|
2711
|
+
paidAmount.toString()
|
|
2712
|
+
],
|
|
2713
|
+
coinType: paymentCoinType,
|
|
2714
|
+
inheritTx: currentTx
|
|
2715
|
+
}, this.sdk.suiClient);
|
|
2716
|
+
txWithCoin.moveCall({
|
|
2717
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::subscription::buy_more_cu`,
|
|
2718
|
+
typeArguments: [
|
|
2719
|
+
paymentCoinType
|
|
2720
|
+
],
|
|
2721
|
+
arguments: [
|
|
2722
|
+
txWithCoin.object(SUBSCRIPTION_CONFIG_ID),
|
|
2723
|
+
txWithCoin.pure.u64(planId),
|
|
2724
|
+
txWithCoin.pure.string(reference),
|
|
2725
|
+
txWithCoin.pure.u64(paidAmount),
|
|
2726
|
+
coinData
|
|
2727
|
+
]
|
|
2728
|
+
});
|
|
2729
|
+
txWithCoin.setSender(walletAddress);
|
|
2730
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, txWithCoin, walletAddress, 0);
|
|
2731
|
+
return addGasFee({
|
|
2732
|
+
inheritTx: txWithCoin,
|
|
2733
|
+
sender: walletAddress,
|
|
2734
|
+
feeAmount: gasAmount
|
|
2735
|
+
}, this.sdk.suiClient);
|
|
2736
|
+
}
|
|
2737
|
+
/**
|
|
2738
|
+
* Builds a transaction for subscribing with admin privileges.
|
|
2739
|
+
* Allows specifying a custom payment amount instead of using the plan's default price.
|
|
2740
|
+
* Useful for promotions, discounts, or special cases.
|
|
2741
|
+
*
|
|
2742
|
+
* **Requires admin capability.**
|
|
2743
|
+
*
|
|
2744
|
+
* @param request - Admin subscription request parameters
|
|
2745
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2746
|
+
* @throws Error if contract is paused
|
|
2747
|
+
*/ async buildSubscribePlanWithAdminTx({ walletAddress, planId, reference, customAmount, paymentCoinType = PAYMENT_COIN_TYPE, currentTx }) {
|
|
2748
|
+
const configObj = await this.getConfig();
|
|
2749
|
+
tiny_invariant(!configObj.paused, "Contract is paused");
|
|
2750
|
+
// Get USDC coins from user's wallet
|
|
2751
|
+
const { tx: txWithCoin, coinData } = await getSplitCoinForTx({
|
|
2752
|
+
account: walletAddress,
|
|
2753
|
+
amount: customAmount.toString(),
|
|
2754
|
+
splits: [
|
|
2755
|
+
customAmount.toString()
|
|
2756
|
+
],
|
|
2757
|
+
coinType: paymentCoinType,
|
|
2758
|
+
inheritTx: currentTx
|
|
2759
|
+
}, this.sdk.suiClient);
|
|
2760
|
+
txWithCoin.moveCall({
|
|
2761
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::subscription::subscribe_plan_with_admin`,
|
|
2762
|
+
typeArguments: [
|
|
2763
|
+
paymentCoinType
|
|
2764
|
+
],
|
|
2765
|
+
arguments: [
|
|
2766
|
+
txWithCoin.object(SUBSCRIPTION_ADMIN_CAP_ID),
|
|
2767
|
+
txWithCoin.object(SUBSCRIPTION_CONFIG_ID),
|
|
2768
|
+
txWithCoin.pure.u64(planId),
|
|
2769
|
+
txWithCoin.pure.string(reference),
|
|
2770
|
+
txWithCoin.pure.u64(customAmount),
|
|
2771
|
+
coinData
|
|
2772
|
+
]
|
|
2773
|
+
});
|
|
2774
|
+
txWithCoin.setSender(walletAddress);
|
|
2775
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, txWithCoin, walletAddress, 0);
|
|
2776
|
+
return addGasFee({
|
|
2777
|
+
inheritTx: txWithCoin,
|
|
2778
|
+
sender: walletAddress,
|
|
2779
|
+
feeAmount: gasAmount
|
|
2780
|
+
}, this.sdk.suiClient);
|
|
2781
|
+
}
|
|
2782
|
+
/**
|
|
2783
|
+
* Builds a transaction for adding a new subscription plan.
|
|
2784
|
+
*
|
|
2785
|
+
* **Requires admin capability.**
|
|
2786
|
+
*
|
|
2787
|
+
* @param request - Add plan request parameters
|
|
2788
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2789
|
+
*/ async buildAddPlanTx({ adminAddress, planId, planType, monthInterval, price, currentTx }) {
|
|
2790
|
+
const tx = currentTx || new Transaction();
|
|
2791
|
+
tx.moveCall({
|
|
2792
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::config::add_plan`,
|
|
2793
|
+
typeArguments: [],
|
|
2794
|
+
arguments: [
|
|
2795
|
+
tx.object(SUBSCRIPTION_CONFIG_ID),
|
|
2796
|
+
tx.object(SUBSCRIPTION_ADMIN_CAP_ID),
|
|
2797
|
+
tx.pure.u64(planId),
|
|
2798
|
+
tx.pure.u8(planType),
|
|
2799
|
+
tx.pure.u8(monthInterval),
|
|
2800
|
+
tx.pure.u64(price)
|
|
2801
|
+
]
|
|
2802
|
+
});
|
|
2803
|
+
tx.setSender(adminAddress);
|
|
2804
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2805
|
+
return addGasFee({
|
|
2806
|
+
inheritTx: tx,
|
|
2807
|
+
sender: adminAddress,
|
|
2808
|
+
feeAmount: gasAmount
|
|
2809
|
+
}, this.sdk.suiClient);
|
|
2810
|
+
}
|
|
2811
|
+
/**
|
|
2812
|
+
* Builds a transaction for updating an existing subscription plan.
|
|
2813
|
+
*
|
|
2814
|
+
* **Requires admin capability.**
|
|
2815
|
+
*
|
|
2816
|
+
* @param request - Update plan request parameters
|
|
2817
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2818
|
+
*/ async buildUpdatePlanTx({ adminAddress, planId, planType, monthInterval, price, currentTx }) {
|
|
2819
|
+
const tx = currentTx || new Transaction();
|
|
2820
|
+
tx.moveCall({
|
|
2821
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::config::update_plan`,
|
|
2822
|
+
typeArguments: [],
|
|
2823
|
+
arguments: [
|
|
2824
|
+
tx.object(SUBSCRIPTION_CONFIG_ID),
|
|
2825
|
+
tx.object(SUBSCRIPTION_ADMIN_CAP_ID),
|
|
2826
|
+
tx.pure.u64(BigInt(planId)),
|
|
2827
|
+
tx.pure.u8(planType),
|
|
2828
|
+
tx.pure.u8(monthInterval),
|
|
2829
|
+
tx.pure.u64(price)
|
|
2830
|
+
]
|
|
2831
|
+
});
|
|
2832
|
+
tx.setSender(adminAddress);
|
|
2833
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2834
|
+
return addGasFee({
|
|
2835
|
+
inheritTx: tx,
|
|
2836
|
+
sender: adminAddress,
|
|
2837
|
+
feeAmount: gasAmount
|
|
2838
|
+
}, this.sdk.suiClient);
|
|
2839
|
+
}
|
|
2840
|
+
/**
|
|
2841
|
+
* Builds a transaction for removing a subscription plan.
|
|
2842
|
+
*
|
|
2843
|
+
* **Requires admin capability.**
|
|
2844
|
+
*
|
|
2845
|
+
* @param request - Remove plan request parameters
|
|
2846
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2847
|
+
*/ async buildRemovePlanTx({ adminAddress, planId, currentTx }) {
|
|
2848
|
+
const tx = currentTx || new Transaction();
|
|
2849
|
+
tx.moveCall({
|
|
2850
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::config::remove_plan`,
|
|
2851
|
+
typeArguments: [],
|
|
2852
|
+
arguments: [
|
|
2853
|
+
tx.object(SUBSCRIPTION_CONFIG_ID),
|
|
2854
|
+
tx.object(SUBSCRIPTION_ADMIN_CAP_ID),
|
|
2855
|
+
tx.pure.u64(BigInt(planId))
|
|
2856
|
+
]
|
|
2857
|
+
});
|
|
2858
|
+
tx.setSender(adminAddress);
|
|
2859
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2860
|
+
return addGasFee({
|
|
2861
|
+
inheritTx: tx,
|
|
2862
|
+
sender: adminAddress,
|
|
2863
|
+
feeAmount: gasAmount
|
|
2864
|
+
}, this.sdk.suiClient);
|
|
2865
|
+
}
|
|
2866
|
+
/**
|
|
2867
|
+
* Builds a transaction for updating the admin wallet address.
|
|
2868
|
+
*
|
|
2869
|
+
* **Requires admin capability.**
|
|
2870
|
+
*
|
|
2871
|
+
* @param request - Update admin wallet request parameters
|
|
2872
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2873
|
+
*/ async buildUpdateFeeReceiverWalletTx({ adminAddress, newFeeReceiverWallet, currentTx }) {
|
|
2874
|
+
const tx = currentTx || new Transaction();
|
|
2875
|
+
tx.moveCall({
|
|
2876
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::config::update_fee_receiver`,
|
|
2877
|
+
typeArguments: [],
|
|
2878
|
+
arguments: [
|
|
2879
|
+
tx.object(SUBSCRIPTION_CONFIG_ID),
|
|
2880
|
+
tx.object(SUBSCRIPTION_ADMIN_CAP_ID),
|
|
2881
|
+
tx.pure.address(newFeeReceiverWallet)
|
|
2882
|
+
]
|
|
2883
|
+
});
|
|
2884
|
+
tx.setSender(adminAddress);
|
|
2885
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2886
|
+
return addGasFee({
|
|
2887
|
+
inheritTx: tx,
|
|
2888
|
+
sender: adminAddress,
|
|
2889
|
+
feeAmount: gasAmount
|
|
2890
|
+
}, this.sdk.suiClient);
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Builds a transaction for pausing or unpausing the contract.
|
|
2894
|
+
*
|
|
2895
|
+
* **Requires admin capability.**
|
|
2896
|
+
*
|
|
2897
|
+
* @param request - Set paused request parameters
|
|
2898
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2899
|
+
*/ async buildSetPausedTx({ adminAddress, paused, currentTx }) {
|
|
2900
|
+
const tx = currentTx || new Transaction();
|
|
2901
|
+
tx.moveCall({
|
|
2902
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::config::set_paused`,
|
|
2903
|
+
typeArguments: [],
|
|
2904
|
+
arguments: [
|
|
2905
|
+
tx.object(SUBSCRIPTION_CONFIG_ID),
|
|
2906
|
+
tx.object(SUBSCRIPTION_ADMIN_CAP_ID),
|
|
2907
|
+
tx.pure.bool(paused)
|
|
2908
|
+
]
|
|
2909
|
+
});
|
|
2910
|
+
tx.setSender(adminAddress);
|
|
2911
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2912
|
+
return addGasFee({
|
|
2913
|
+
inheritTx: tx,
|
|
2914
|
+
sender: adminAddress,
|
|
2915
|
+
feeAmount: gasAmount
|
|
2916
|
+
}, this.sdk.suiClient);
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Builds a transaction to set the accepted payment coin type.
|
|
2920
|
+
* Note: Only one payment type can be accepted at a time. Setting a new type replaces the previous one.
|
|
2921
|
+
*
|
|
2922
|
+
* **Requires admin capability.**
|
|
2923
|
+
*
|
|
2924
|
+
* @param request - Set accepted payment type request parameters
|
|
2925
|
+
* @returns Promise resolving to a transaction ready for execution
|
|
2926
|
+
*/ async buildSetAcceptedPaymentTypeTx({ adminAddress, paymentCoinType, currentTx }) {
|
|
2927
|
+
const tx = currentTx || new Transaction();
|
|
2928
|
+
tx.moveCall({
|
|
2929
|
+
target: `${SUBSCRIPTION_PACKAGE_ID}::config::set_accepted_payment_type`,
|
|
2930
|
+
typeArguments: [
|
|
2931
|
+
paymentCoinType
|
|
2932
|
+
],
|
|
2933
|
+
arguments: [
|
|
2934
|
+
tx.object(SUBSCRIPTION_CONFIG_ID),
|
|
2935
|
+
tx.object(SUBSCRIPTION_ADMIN_CAP_ID)
|
|
2936
|
+
]
|
|
2937
|
+
});
|
|
2938
|
+
tx.setSender(adminAddress);
|
|
2939
|
+
const gasAmount = await getNeededGasFee(this.sdk.suiClient, tx, adminAddress, 0);
|
|
2940
|
+
return addGasFee({
|
|
2941
|
+
inheritTx: tx,
|
|
2942
|
+
sender: adminAddress,
|
|
2943
|
+
feeAmount: gasAmount
|
|
2944
|
+
}, this.sdk.suiClient);
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
;// CONCATENATED MODULE: ./src/modules/index.ts
|
|
2949
|
+
|
|
2950
|
+
|
|
2951
|
+
|
|
2952
|
+
|
|
2953
|
+
|
|
2954
|
+
|
|
2955
|
+
;// CONCATENATED MODULE: ./src/pay-sdk.ts
|
|
2956
|
+
|
|
2957
|
+
|
|
2958
|
+
class NoodlesPaySdk {
|
|
2959
|
+
_suiClient;
|
|
2960
|
+
boostingModule;
|
|
2961
|
+
subscriptionModule;
|
|
2962
|
+
constructor(){
|
|
2963
|
+
this._suiClient = new SuiClient({
|
|
2964
|
+
url: getFullnodeUrl("mainnet")
|
|
2965
|
+
});
|
|
2966
|
+
this.subscriptionModule = new SubscriptionModule(this);
|
|
2967
|
+
this.boostingModule = new BoostingModule(this);
|
|
2968
|
+
}
|
|
2969
|
+
get suiClient() {
|
|
2970
|
+
return this._suiClient;
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
;// CONCATENATED MODULE: ./src/sdk.ts
|
|
2975
|
+
|
|
2976
|
+
|
|
2977
|
+
const DEFAULT_TRADE_FEE = {
|
|
2978
|
+
tradeFeePercent: 0.01,
|
|
2979
|
+
tradeFeeRecipientAddress: "0xdaf1c8ed29d89cd8f217f609bad0a668fa6f158c12000bfa5f93e670c99e24ff"
|
|
2980
|
+
};
|
|
2981
|
+
class NoodlesSdk {
|
|
2982
|
+
options;
|
|
2983
|
+
_suiClient;
|
|
2984
|
+
aggregatorModule;
|
|
2985
|
+
curveModule;
|
|
2986
|
+
constructor(options){
|
|
2987
|
+
this.options = options;
|
|
2988
|
+
this._suiClient = new SuiClient({
|
|
2989
|
+
url: getFullnodeUrl("mainnet")
|
|
2990
|
+
});
|
|
2991
|
+
this.aggregatorModule = new AggregatorModule(this);
|
|
2992
|
+
this.curveModule = new CurveModule(this);
|
|
2993
|
+
}
|
|
2994
|
+
get suiClient() {
|
|
2995
|
+
return this._suiClient;
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
;// CONCATENATED MODULE: external "@mysten/sui/keypairs/ed25519"
|
|
3000
|
+
|
|
3001
|
+
;// CONCATENATED MODULE: ./src/transaction/draft-transfer.ts
|
|
3002
|
+
|
|
3003
|
+
|
|
3004
|
+
|
|
3005
|
+
|
|
3006
|
+
|
|
3007
|
+
// Constants
|
|
3008
|
+
const CONSTANTS = {
|
|
3009
|
+
GAS_FEE_BUFFER_PERCENTAGE: 0.1
|
|
3010
|
+
};
|
|
3011
|
+
class DraftTransferTx {
|
|
3012
|
+
suiClient;
|
|
3013
|
+
constructor(suiClient){
|
|
3014
|
+
this.suiClient = suiClient;
|
|
3015
|
+
}
|
|
3016
|
+
/**
|
|
3017
|
+
* Validates private key against expected sender address
|
|
3018
|
+
* @private
|
|
3019
|
+
*/ validatePrivateKey(privateKey, expectedSender) {
|
|
3020
|
+
tiny_invariant(privateKey?.trim(), "Private key is required");
|
|
3021
|
+
const keypair = Ed25519Keypair.fromSecretKey(privateKey);
|
|
3022
|
+
const derivedAddress = keypair.getPublicKey().toSuiAddress();
|
|
3023
|
+
if (derivedAddress !== expectedSender) {
|
|
3024
|
+
throw new Error(`Private key mismatch. Expected: ${expectedSender}, Got: ${derivedAddress}`);
|
|
3025
|
+
}
|
|
3026
|
+
return keypair;
|
|
3027
|
+
}
|
|
3028
|
+
/**
|
|
3029
|
+
* Creates a draft transaction for SUI transfer
|
|
3030
|
+
* @param params - Transfer parameters
|
|
3031
|
+
* @returns Draft transaction object with encoded transaction data
|
|
3032
|
+
* @throws {Error} If validation fails or transaction building fails
|
|
3033
|
+
*/ async createDraft(sender, recipient, amountMIST) {
|
|
3034
|
+
tiny_invariant(sender?.trim(), "Sender address is required");
|
|
3035
|
+
tiny_invariant(recipient?.trim(), "Recipient address is required");
|
|
3036
|
+
tiny_invariant(sender !== recipient, "Sender and recipient cannot be the same");
|
|
3037
|
+
tiny_invariant(amountMIST > 0n, "Transfer amount must be at least 1 MIST");
|
|
3038
|
+
try {
|
|
3039
|
+
// Build the transaction
|
|
3040
|
+
let transaction = new Transaction();
|
|
3041
|
+
const [coin] = transaction.splitCoins(transaction.gas, [
|
|
3042
|
+
amountMIST
|
|
3043
|
+
]);
|
|
3044
|
+
transaction.transferObjects([
|
|
3045
|
+
coin
|
|
3046
|
+
], recipient);
|
|
3047
|
+
transaction.setSender(sender);
|
|
3048
|
+
// Set gas configuration
|
|
3049
|
+
const referenceGasPrice = await this.suiClient.getReferenceGasPrice();
|
|
3050
|
+
transaction.setGasPrice(referenceGasPrice);
|
|
3051
|
+
// Calculate and set gas budget
|
|
3052
|
+
const feeAmount = await getNeededGasFee(this.suiClient, transaction, sender, CONSTANTS.GAS_FEE_BUFFER_PERCENTAGE);
|
|
3053
|
+
transaction = await addGasFee({
|
|
3054
|
+
inheritTx: transaction,
|
|
3055
|
+
sender,
|
|
3056
|
+
feeAmount,
|
|
3057
|
+
suiInputAmount: amountMIST
|
|
3058
|
+
}, this.suiClient);
|
|
3059
|
+
// Build and encode transaction
|
|
3060
|
+
const txBytes = await transaction.build({
|
|
3061
|
+
client: this.suiClient
|
|
3062
|
+
});
|
|
3063
|
+
const txDraftBase64 = Buffer.from(txBytes).toString("base64");
|
|
3064
|
+
const txDigest = await transaction.getDigest();
|
|
3065
|
+
return {
|
|
3066
|
+
sender,
|
|
3067
|
+
recipient,
|
|
3068
|
+
amountMIST,
|
|
3069
|
+
txDraftBase64,
|
|
3070
|
+
txDigest
|
|
3071
|
+
};
|
|
3072
|
+
} catch (error) {
|
|
3073
|
+
throw new Error(`Failed to create draft transaction: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
/**
|
|
3077
|
+
* Executes a draft transaction on the Sui network
|
|
3078
|
+
* @param draftTx - Draft transaction to execute
|
|
3079
|
+
* @param privateKey - Sender's private key
|
|
3080
|
+
* @returns Execution result with success status and transaction details
|
|
3081
|
+
*/ async execute(draftTx, privateKey) {
|
|
3082
|
+
try {
|
|
3083
|
+
tiny_invariant(draftTx, "Draft transaction is required");
|
|
3084
|
+
tiny_invariant(draftTx.txDraftBase64?.trim(), "Transaction data is required");
|
|
3085
|
+
// Validate private key and get keypair
|
|
3086
|
+
const keypair = this.validatePrivateKey(privateKey, draftTx.sender);
|
|
3087
|
+
// Decode and sign transaction
|
|
3088
|
+
const txBytes = fromBase64(draftTx.txDraftBase64);
|
|
3089
|
+
const { signature } = await keypair.signTransaction(txBytes);
|
|
3090
|
+
// Execute on network
|
|
3091
|
+
const result = await this.suiClient.executeTransactionBlock({
|
|
3092
|
+
transactionBlock: txBytes,
|
|
3093
|
+
signature
|
|
3094
|
+
});
|
|
3095
|
+
return {
|
|
3096
|
+
success: true,
|
|
3097
|
+
txDigest: result.digest,
|
|
3098
|
+
effects: result.effects
|
|
3099
|
+
};
|
|
3100
|
+
} catch (error) {
|
|
3101
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
3102
|
+
return {
|
|
3103
|
+
success: false,
|
|
3104
|
+
error: errorMessage
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
/**
|
|
3109
|
+
* Verifies the status of a transaction on the Sui network
|
|
3110
|
+
* @param txDigest - Transaction digest to check
|
|
3111
|
+
* @returns Transaction status: 'success', 'failure', or 'pending'
|
|
3112
|
+
*/ async getTransactionStatus(txDigest) {
|
|
3113
|
+
tiny_invariant(txDigest?.trim(), "Transaction digest is required");
|
|
3114
|
+
try {
|
|
3115
|
+
const txResponse = await this.suiClient.getTransactionBlock({
|
|
3116
|
+
digest: txDigest,
|
|
3117
|
+
options: {
|
|
3118
|
+
showEffects: true
|
|
3119
|
+
}
|
|
3120
|
+
});
|
|
3121
|
+
if (!txResponse?.effects?.status) {
|
|
3122
|
+
return "pending";
|
|
3123
|
+
}
|
|
3124
|
+
return txResponse.effects.status.status === "success" ? "success" : "failure";
|
|
3125
|
+
} catch (error) {
|
|
3126
|
+
if (error instanceof Error) {
|
|
3127
|
+
// Transaction not found indicates it's still pending
|
|
3128
|
+
if (error.message.includes("not found") || error.message.includes("Could not find")) {
|
|
3129
|
+
return "pending";
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
return "failure";
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
;// CONCATENATED MODULE: ./src/transaction/index.ts
|
|
3138
|
+
|
|
3139
|
+
|
|
3140
|
+
;// CONCATENATED MODULE: ./src/exports/index.ts
|
|
3141
|
+
|
|
3142
|
+
|
|
3143
|
+
|
|
3144
|
+
|
|
3145
|
+
|
|
3146
|
+
|
|
3147
|
+
|
|
3148
|
+
|
|
3149
|
+
|
|
3150
|
+
|
|
3151
|
+
var __webpack_exports__BASE_BPS = /* inlined export .BASE_BPS */ (10000);
|
|
3152
|
+
export { ADMIN_CAP_ID, aftermath_AftermathAggregator as AftermathAggregator, AggregatorModule, astros_AstrosAggregator as AstrosAggregator, BLUEFIN_PACKAGE_ID, BOOSTING_PACKAGE_ID, constants_BlastFunConstants as BlastFunConstants, custom_calculation_BlastFunCustomCalculation as BlastFunCustomCalculation, custom_transaction_BlastFunCustomTransaction as BlastFunCustomTransaction, package_BlastFunPackage as BlastFunPackage, sdk_calculation_BlastFunSDKCalculation as BlastFunSDKCalculation, sdk_transaction_BlastFunSDKTransaction as BlastFunSDKTransaction, bluefin_BluefinTx as BluefinTx, BoostingModule, package_Bps as Bps, CLOCK_OBJECT_ID, CONFIG_ID, cetus_CetusAggregator as CetusAggregator, CurveModule, DEFAULT_TRADE_FEE, DraftTransferTx, flowx_FlowXAggregator as FlowXAggregator, package_MathUtils as MathUtils, calculation_MoonbagsCalculation as MoonbagsCalculation, constants_MoonbagsConstants as MoonbagsConstants, package_MoonbagsPackage as MoonbagsPackage, transaction_MoonbagsTransaction as MoonbagsTransaction, NATIVE_USDC_TOKEN_TYPE, NoodlesPaySdk, NoodlesSdk, PAYMENT_COIN_TYPE, SUBSCRIPTION_ADMIN_CAP_ID, SUBSCRIPTION_CONFIG_ID, SUBSCRIPTION_PACKAGE_ID, SUI_FULL_TYPE, SUI_METADATA_OBJECT_ID, SUI_TYPE, _7k_SevenKAggregator as SevenKAggregator, SubscriptionModule, common_SupportedAggregator as SupportedAggregator, types_SupportedBondingCurve as SupportedBondingCurve, types_TradeFeeOptions as TradeFeeOptions, USDC_TOKEN_TYPE, adaptSuiClient, adaptTransaction, addGasFee, createCompatibleSuiClient, getAmountAfterFee, getCoinObjectIdsByAmount, getMemezPumpSDK, getMoveObject, getMoveObjectContent, getNeededGasFee, getSplitCoinForTx, getSplitCoinsAfterFee, isSuiCoinType, splitSuiCoinAfterFeeFromBuyTx, splitSuiCoinAfterFeeFromSellTx, __webpack_exports__BASE_BPS as BASE_BPS };
|