@avalabs/fusion-sdk 0.23.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/errors.cjs +1 -1
  2. package/dist/errors.cjs.map +1 -1
  3. package/dist/errors.d.cts +18 -1
  4. package/dist/errors.d.ts +18 -1
  5. package/dist/errors.js +1 -1
  6. package/dist/errors.js.map +1 -1
  7. package/dist/quoter/quoter.cjs.map +1 -1
  8. package/dist/quoter/quoter.d.cts +3 -1
  9. package/dist/quoter/quoter.d.ts +3 -1
  10. package/dist/quoter/quoter.js.map +1 -1
  11. package/dist/transfer-service/markr/_handlers/stream-quotes.cjs +1 -1
  12. package/dist/transfer-service/markr/_handlers/stream-quotes.cjs.map +1 -1
  13. package/dist/transfer-service/markr/_handlers/stream-quotes.js +1 -1
  14. package/dist/transfer-service/markr/_handlers/stream-quotes.js.map +1 -1
  15. package/dist/transfer-service/markr/_schema.cjs +1 -1
  16. package/dist/transfer-service/markr/_schema.cjs.map +1 -1
  17. package/dist/transfer-service/markr/_schema.js +1 -1
  18. package/dist/transfer-service/markr/_schema.js.map +1 -1
  19. package/dist/transfer-service/markr/_utils.cjs +1 -1
  20. package/dist/transfer-service/markr/_utils.cjs.map +1 -1
  21. package/dist/transfer-service/markr/_utils.js +1 -1
  22. package/dist/transfer-service/markr/_utils.js.map +1 -1
  23. package/dist/transfer-service/markr/recurring/_api.cjs +1 -1
  24. package/dist/transfer-service/markr/recurring/_api.cjs.map +1 -1
  25. package/dist/transfer-service/markr/recurring/_api.js +1 -1
  26. package/dist/transfer-service/markr/recurring/_api.js.map +1 -1
  27. package/dist/transfer-service/markr/recurring/_chain-info.cjs +1 -1
  28. package/dist/transfer-service/markr/recurring/_chain-info.cjs.map +1 -1
  29. package/dist/transfer-service/markr/recurring/_chain-info.js +1 -1
  30. package/dist/transfer-service/markr/recurring/_chain-info.js.map +1 -1
  31. package/dist/transfer-service/markr/recurring/_eligibility.cjs +1 -1
  32. package/dist/transfer-service/markr/recurring/_eligibility.cjs.map +1 -1
  33. package/dist/transfer-service/markr/recurring/_eligibility.js +1 -1
  34. package/dist/transfer-service/markr/recurring/_eligibility.js.map +1 -1
  35. package/dist/transfer-service/markr/recurring/_namespace.cjs +1 -1
  36. package/dist/transfer-service/markr/recurring/_namespace.cjs.map +1 -1
  37. package/dist/transfer-service/markr/recurring/_namespace.js +1 -1
  38. package/dist/transfer-service/markr/recurring/_namespace.js.map +1 -1
  39. package/dist/transfer-service/markr/recurring/_schema.cjs +1 -1
  40. package/dist/transfer-service/markr/recurring/_schema.cjs.map +1 -1
  41. package/dist/transfer-service/markr/recurring/_schema.js +1 -1
  42. package/dist/transfer-service/markr/recurring/_schema.js.map +1 -1
  43. package/dist/transfer-service/markr/recurring/types.cjs +1 -1
  44. package/dist/transfer-service/markr/recurring/types.cjs.map +1 -1
  45. package/dist/transfer-service/markr/recurring/types.d.cts +32 -23
  46. package/dist/transfer-service/markr/recurring/types.d.ts +32 -23
  47. package/dist/transfer-service/markr/recurring/types.js +1 -1
  48. package/dist/transfer-service/markr/recurring/types.js.map +1 -1
  49. package/dist/types/service.d.cts +3 -1
  50. package/dist/types/service.d.ts +3 -1
  51. package/package.json +3 -3
@@ -1,2 +1,2 @@
1
- require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../_utils.cjs`),i=require(`../../_evm-errors.cjs`),a=require(`../../_evm-approval.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`./_api.cjs`),l=require(`./_eligibility.cjs`);let u=require(`viem`);function d({apiOptions:t,appId:n,evmSigner:r,recurringChainInfo:i}){return{quote:e=>c.markrRecurringQuote(t,{...e,appId:n}),executeFirstFill:e=>f({...e,apiOptions:t,appId:n,evmSigner:r}),listOrders:e=>c.markrListRecurringOrders(t,e),executeCancellation:n=>m({...n,signatureReason:e.TransferSignatureReason.CancelRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareCancellation}),executePause:n=>m({...n,signatureReason:e.TransferSignatureReason.PauseRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPreparePause}),executeUnpause:n=>m({...n,signatureReason:e.TransferSignatureReason.ResumeRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareUnpause}),checkEligibility:e=>l.checkRecurringEligibility({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function f({apiOptions:l,appId:u,evmSigner:d,fallbackToDefaultOnBatchFailure:f,fromAddress:p,gasSettings:m,quote:g,signerContext:_,sourceChain:v}){let y=Math.floor(Date.now()/1e3);if(g.expiredAt<=y){let e=y-g.expiredAt;throw new t.InvalidParamsError(t.ErrorReason.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let b=n.caip2ToEip155ChainId(v.chainId);if(b!==g.chainId)throw new t.InvalidParamsError(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${v.chainId} resolves to ${b}, but quote.chainId=${g.chainId}.`);let x=r.getEvmClientForChain({chain:v}),S=n.caip2ToEip155HexChainId(v.chainId),{address:C}=await o.markrGetSpenderAddress(l,{chainId:g.chainId,crossChainSwap:!1,quoteId:g.uuid});if(!C)throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${v.chainId}.`});let w=await a.buildErc20ApprovalRequest({chainIdHex:S,client:x,gasSettings:m,owner:p,requiredAllowance:g.totalAmountIn,spender:C,token:g.tokenIn}),T=h({fromAddress:p,quote:g,sourceChain:v}),E=await c.markrRecurringSwap(l,{uuid:g.uuid,appId:u});if(w!==void 0&&typeof d.signBatch==`function`){let n={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:T,requiredSignatures:1,signerContext:_},i={chainId:S,data:E.data,from:p,gas:void 0,to:E.to,value:E.value,...r.maybe1559(m)};try{let e=(await d.signBatch([w,i],e=>x.sendRawTransaction({serializedTransaction:e}),n)).at(-1);if(!e)throw new t.SdkError(`One-click batch signing returned no transaction hashes.`,t.ErrorCode.SIGNING_FAILED);return{txHash:e}}catch(e){if(!f)throw e}}w&&await a.signApprovalAndAssertConfirmed({client:x,evmSigner:d,request:w,step:{currentSignature:1,currentSignatureReason:e.TransferSignatureReason.AllowanceApproval,quote:T,requiredSignatures:2,signerContext:_}});let D=await s.getMarkrSwapWrapperAbi(!1),O=await i.estimateGasWithRevert(x,{account:p,to:E.to,data:E.data,value:E.value},D,`Failed to estimate gas for recurring first-fill swap transaction.`),k={chainId:S,data:E.data,from:p,gas:r.applyFeeUnitsBpsMargin(O,m?.estimateGasMarginBps),to:E.to,value:E.value,...r.maybe1559(m)},A={currentSignature:w?2:1,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:T,requiredSignatures:w?2:1,signerContext:_};return{txHash:await d.sign(k,e=>x.sendRawTransaction({serializedTransaction:e}),A)}}const p={[e.TransferSignatureReason.PauseRecurringSwap]:`pause`,[e.TransferSignatureReason.ResumeRecurringSwap]:`resume`,[e.TransferSignatureReason.CancelRecurringSwap]:`cancel`};async function m({signatureReason:e,address:t,apiOptions:a,evmSigner:o,fetchCalldata:s,gasSettings:c,orderId:l,signerContext:d,sourceChain:f}){let m=r.getEvmClientForChain({chain:f}),h=n.caip2ToEip155ChainId(f.chainId),_=n.caip2ToEip155HexChainId(f.chainId),v=await s(a,{orderId:l,address:t,chainId:h}),y=await i.estimateGasWithRevert(m,{account:t,to:v.to,data:v.data,value:v.value},u.erc20Abi,`Failed to estimate gas for recurring ${p[e]} transaction.`),b={chainId:_,data:v.data,from:t,gas:r.applyFeeUnitsBpsMargin(y,c?.estimateGasMarginBps),to:v.to,value:v.value,...r.maybe1559(c)},x={currentSignature:1,currentSignatureReason:e,quote:g({address:t,signatureReason:e,orderId:l,sourceChain:f}),requiredSignatures:1,signerContext:d};return{txHash:await o.sign(b,e=>m.sendRawTransaction({serializedTransaction:e}),x)}}function h({fromAddress:t,quote:n,sourceChain:r}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:n.amount,amountOut:n.amountOut,assetIn:{type:e.TokenType.ERC20,address:n.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:e.TokenType.ERC20,address:n.tokenOut,name:``,symbol:``,decimals:0},expiresAt:n.expiredAt,fees:[],fromAddress:t,id:n.uuid,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:n.recommendedSlippage,sourceChain:r,targetChain:r,toAddress:t}}function g({signatureReason:t,address:n,orderId:r,sourceChain:i}){let a=p[t];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:_(),assetOut:_(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function _(){return{type:e.TokenType.NATIVE,name:``,symbol:``,decimals:0}}exports.createRecurringNamespace=d;
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../_utils.cjs`),i=require(`../../_evm-errors.cjs`),a=require(`../../_evm-approval.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`./_api.cjs`),l=require(`./_eligibility.cjs`);let u=require(`viem`);function d({apiOptions:t,appId:n,evmSigner:r,recurringChainInfo:i}){return{quote:e=>f({...e,apiOptions:t,appId:n,recurringChainInfo:i}),executeFirstFill:e=>p({...e,apiOptions:t,appId:n,evmSigner:r,recurringChainInfo:i}),listOrders:e=>c.markrListRecurringOrders(t,e),executeCancellation:n=>g({...n,signatureReason:e.TransferSignatureReason.CancelRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareCancellation}),executePause:n=>g({...n,signatureReason:e.TransferSignatureReason.PauseRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPreparePause}),executeUnpause:n=>g({...n,signatureReason:e.TransferSignatureReason.ResumeRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareUnpause}),checkEligibility:e=>l.checkRecurringEligibility({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function f({apiOptions:e,appId:n,recurringChainInfo:r,...i}){if((0,u.isAddressEqual)(i.tokenIn,`0x0000000000000000000000000000000000000000`)&&!r.get(i.chainId)?.wrappedNativeAddress)throw new t.InvalidParamsError(t.ErrorReason.CHAIN_NOT_SUPPORTED,`No wrapped-native ERC-20 address known for EVM chainId ${i.chainId}. Native-input recurring swaps require Markr to publish \`wrapped_token\` for the chain in \`/info/chains\`.`);return c.markrRecurringQuote(e,{...i,appId:n})}async function p({apiOptions:l,appId:d,evmSigner:f,fallbackToDefaultOnBatchFailure:p,fromAddress:h,gasSettings:g,quote:v,recurringChainInfo:y,signerContext:b,sourceChain:x}){let S=Math.floor(Date.now()/1e3);if(v.expiredAt<=S){let e=S-v.expiredAt;throw new t.InvalidParamsError(t.ErrorReason.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let C=n.caip2ToEip155ChainId(x.chainId);if(C!==v.chainId)throw new t.InvalidParamsError(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${x.chainId} resolves to ${C}, but quote.chainId=${v.chainId}.`);let w=r.getEvmClientForChain({chain:x}),T=n.caip2ToEip155HexChainId(x.chainId),E=(0,u.isAddressEqual)(v.tokenIn,e.ERC_ZERO_ADDRESS),{address:D}=await o.markrGetSpenderAddress(l,{chainId:v.chainId,crossChainSwap:!1,quoteId:v.uuid});if(!D)throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${x.chainId}.`});let O=await c.markrRecurringSwap(l,{uuid:v.uuid,appId:d}),k=O.find(e=>e.type===`wrap`),A=O.find(e=>e.type===`createOrder`);if(!A)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Missing createOrder step (quote uuid: ${v.uuid}).`});if(E&&!k)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Native-input quote returned no wrap step (quote uuid: ${v.uuid}).`});if(!E&&k)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`ERC-20 input quote returned a wrap step (quote uuid: ${v.uuid}, tokenIn: ${v.tokenIn}).`});if(k){if(k.value!==v.totalAmountIn)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Wrap step value ${k.value} does not match quote.totalAmountIn ${v.totalAmountIn} (quote uuid: ${v.uuid}).`});let e=y.get(v.chainId)?.wrappedNativeAddress;if(e&&!(0,u.isAddressEqual)(k.to,e))throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Wrap step target ${k.to} does not match the published wrapped-native ${e} for chainId ${v.chainId} (quote uuid: ${v.uuid}).`})}let j=k?.to??v.tokenIn,M=await a.buildErc20ApprovalRequest({chainIdHex:T,client:w,gasSettings:g,owner:h,requiredAllowance:v.totalAmountIn,spender:D,token:j}),N=k?{chainId:T,data:k.data,from:h,gas:void 0,to:k.to,value:k.value,...r.maybe1559(g)}:void 0,P=_({fromAddress:h,quote:v,sourceChain:x}),F=[];if(N&&F.push(N),M&&F.push(M),F.length>0&&typeof f.signBatch==`function`){let n={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:P,requiredSignatures:1,signerContext:b},i={chainId:T,data:A.data,from:h,gas:void 0,to:A.to,value:A.value,...r.maybe1559(g)};try{let e=(await f.signBatch([...F,i],e=>w.sendRawTransaction({serializedTransaction:e}),n)).at(-1);if(!e)throw new t.SdkError(`One-click batch signing returned no transaction hashes.`,t.ErrorCode.SIGNING_FAILED);return{txHash:e}}catch(e){if(!p)throw e}}let I=1+F.length,L=0;if(N&&k){let t=await i.estimateGasWithRevert(w,{account:h,to:k.to,data:k.data,value:k.value},[],`Failed to estimate gas for recurring first-fill wrap transaction.`),n={...N,gas:r.applyFeeUnitsBpsMargin(t,g?.estimateGasMarginBps)};L+=1,await m({client:w,evmSigner:f,request:n,step:{currentSignature:L,currentSignatureReason:e.TransferSignatureReason.WrapToken,quote:P,requiredSignatures:I,signerContext:b}})}M&&(L+=1,await a.signApprovalAndAssertConfirmed({client:w,evmSigner:f,request:M,step:{currentSignature:L,currentSignatureReason:e.TransferSignatureReason.AllowanceApproval,quote:P,requiredSignatures:I,signerContext:b}}));let R=await s.getMarkrSwapWrapperAbi(!1),z=await i.estimateGasWithRevert(w,{account:h,to:A.to,data:A.data,value:A.value},R,`Failed to estimate gas for recurring first-fill swap transaction.`),B={chainId:T,data:A.data,from:h,gas:r.applyFeeUnitsBpsMargin(z,g?.estimateGasMarginBps),to:A.to,value:A.value,...r.maybe1559(g)};L+=1;let V={currentSignature:L,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:P,requiredSignatures:I,signerContext:b};return{txHash:await f.sign(B,e=>w.sendRawTransaction({serializedTransaction:e}),V)}}async function m({client:e,evmSigner:n,request:r,step:i}){let a=await n.sign(r,t=>e.sendRawTransaction({serializedTransaction:t}),i);if((await e.waitForTransactionReceipt({hash:a})).status===`reverted`)throw new t.SdkError(t.ErrorReason.NATIVE_WRAP_REVERTED,t.ErrorCode.TRANSACTION_REVERTED,{details:`Wrap tx reverted on-chain (tx hash: ${a}).`});return a}const h={[e.TransferSignatureReason.PauseRecurringSwap]:`pause`,[e.TransferSignatureReason.ResumeRecurringSwap]:`resume`,[e.TransferSignatureReason.CancelRecurringSwap]:`cancel`};async function g({signatureReason:e,address:t,apiOptions:a,evmSigner:o,fetchCalldata:s,gasSettings:c,orderId:l,signerContext:d,sourceChain:f}){let p=r.getEvmClientForChain({chain:f}),m=n.caip2ToEip155ChainId(f.chainId),g=n.caip2ToEip155HexChainId(f.chainId),_=await s(a,{orderId:l,address:t,chainId:m}),y=await i.estimateGasWithRevert(p,{account:t,to:_.to,data:_.data,value:_.value},u.erc20Abi,`Failed to estimate gas for recurring ${h[e]} transaction.`),b={chainId:g,data:_.data,from:t,gas:r.applyFeeUnitsBpsMargin(y,c?.estimateGasMarginBps),to:_.to,value:_.value,...r.maybe1559(c)},x={currentSignature:1,currentSignatureReason:e,quote:v({address:t,signatureReason:e,orderId:l,sourceChain:f}),requiredSignatures:1,signerContext:d};return{txHash:await o.sign(b,e=>p.sendRawTransaction({serializedTransaction:e}),x)}}function _({fromAddress:t,quote:n,sourceChain:r}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:n.amount,amountOut:n.amountOut,assetIn:{type:e.TokenType.ERC20,address:n.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:e.TokenType.ERC20,address:n.tokenOut,name:``,symbol:``,decimals:0},expiresAt:n.expiredAt,fees:[],fromAddress:t,id:n.uuid,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:n.recommendedSlippage,sourceChain:r,targetChain:r,toAddress:t}}function v({signatureReason:t,address:n,orderId:r,sourceChain:i}){let a=h[t];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:y(),assetOut:y(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function y(){return{type:e.TokenType.NATIVE,name:``,symbol:``,decimals:0}}exports.createRecurringNamespace=d;
2
2
  //# sourceMappingURL=_namespace.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_namespace.cjs","names":["markrRecurringQuote","markrListRecurringOrders","TransferSignatureReason","markrPrepareCancellation","markrPreparePause","markrPrepareUnpause","checkRecurringEligibility","InvalidParamsError","ErrorReason","caip2ToEip155ChainId","getEvmClientForChain","caip2ToEip155HexChainId","markrGetSpenderAddress","SdkError","ErrorCode","buildErc20ApprovalRequest","markrRecurringSwap","maybe1559","signApprovalAndAssertConfirmed","getMarkrSwapWrapperAbi","estimateGasWithRevert","applyFeeUnitsBpsMargin","erc20Abi","TokenType","ServiceType"],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi } from 'viem';\nimport { ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => markrRecurringQuote(apiOptions, { ...props, appId }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: quote.tokenIn,\n });\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n const swap = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n // One-click batch path: same-chain DCA, approval required, signer exposes\n // `signBatch`. Matches `_executeEvmTransfer`'s eligibility check (recurring\n // is always same-chain so the cross-chain check there collapses to true).\n if (approvalRequest !== undefined && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the approval hasn't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [approvalRequest, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the two-signature path below.\n }\n }\n\n if (approvalRequest) {\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures: 2,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: swap.to, data: swap.data, value: swap.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n const swapStep: TransferStepDetails = {\n currentSignature: approvalRequest ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: approvalRequest ? 2 : 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_namespace.cjs","names":["markrListRecurringOrders","TransferSignatureReason","markrPrepareCancellation","markrPreparePause","markrPrepareUnpause","checkRecurringEligibility","InvalidParamsError","ErrorReason","markrRecurringQuote","caip2ToEip155ChainId","getEvmClientForChain","caip2ToEip155HexChainId","ERC_ZERO_ADDRESS","markrGetSpenderAddress","SdkError","ErrorCode","markrRecurringSwap","buildErc20ApprovalRequest","maybe1559","estimateGasWithRevert","applyFeeUnitsBpsMargin","signApprovalAndAssertConfirmed","getMarkrSwapWrapperAbi","erc20Abi","TokenType","ServiceType"],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi, isAddressEqual } from 'viem';\nimport { ERC_ZERO_ADDRESS, ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest, Hex } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport type { EvmSourceClient } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringNamespaceQuoteParams,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => quoteImpl({ ...props, apiOptions, appId, recurringChainInfo }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner, recurringChainInfo }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Quote — native input (`tokenIn === 0x0…`) is passed through to Markr\n// verbatim (the recurring API accepts the zero address as `tokenIn`). The\n// chain's wrapped-native address is read off the cached chain info (sourced\n// from `/info/chains[].wrapped_token`); the SDK only fails fast at this\n// boundary when Markr hasn't published one for the chain — we'd be issuing\n// a quote we couldn't honor.\n// ---------------------------------------------------------------------------\n\ninterface QuoteImplParams extends RecurringNamespaceQuoteParams {\n apiOptions: ApiOptions;\n appId: string;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function quoteImpl({\n apiOptions,\n appId,\n recurringChainInfo,\n ...quoteParams\n}: QuoteImplParams): Promise<RecurringQuoteResponse> {\n const isNativeInput = isAddressEqual(quoteParams.tokenIn, ERC_ZERO_ADDRESS);\n\n if (isNativeInput && !recurringChainInfo.get(quoteParams.chainId)?.wrappedNativeAddress) {\n throw new InvalidParamsError(\n ErrorReason.CHAIN_NOT_SUPPORTED,\n `No wrapped-native ERC-20 address known for EVM chainId ${quoteParams.chainId}. ` +\n 'Native-input recurring swaps require Markr to publish `wrapped_token` for the chain in `/info/chains`.',\n );\n }\n\n return markrRecurringQuote(apiOptions, { ...quoteParams, appId });\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n recurringChainInfo,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const isNativeInput = isAddressEqual(quote.tokenIn, ERC_ZERO_ADDRESS);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n // Fetch the ordered transaction array from Markr's `/recurring/swap`:\n // - ERC-20 `tokenIn`: `[createOrder]` (1 element).\n // - Native `tokenIn` (`0x0…`): `[wrap, createOrder]` (2 elements).\n // The wrap's `to` is the wrapped-native ERC-20 we'll then approve against\n // (Markr does not return an approval entry — the SDK inserts that step).\n const recurringSwapTxs = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n const wrapTx = recurringSwapTxs.find((tx) => tx.type === 'wrap');\n const createOrderTx = recurringSwapTxs.find((tx) => tx.type === 'createOrder');\n\n if (!createOrderTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Missing createOrder step (quote uuid: ${quote.uuid}).`,\n });\n }\n\n // Cross-check: native input must come back with a wrap leg, and an ERC-20\n // input must not. If Markr disagrees with the cached quote's `tokenIn`,\n // bail rather than silently signing a mismatched flow (e.g. broadcasting\n // a wrap when the user thought they were spending ERC-20, or skipping a\n // wrap when the user expected to fund the schedule with native).\n if (isNativeInput && !wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Native-input quote returned no wrap step (quote uuid: ${quote.uuid}).`,\n });\n }\n if (!isNativeInput && wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `ERC-20 input quote returned a wrap step (quote uuid: ${quote.uuid}, tokenIn: ${quote.tokenIn}).`,\n });\n }\n\n // Defense-in-depth on the wrap leg before we hand it to the wallet:\n // - `wrap.value` must equal `quote.totalAmountIn` — that's what funds the\n // full schedule; a smaller value would under-fund subsequent fills, a\n // larger one would silently overcharge the user.\n // - `wrap.to` must match the chain's published wrapped-native (from\n // `/info/chains[].wrapped_token`) when one is known. Cross-check guards\n // against a misrouted approval — we're about to grant `totalAmountIn`\n // allowance to whatever `wrap.to` points at. When the chain entry has\n // no published wrapped-native, defer to Markr (`wrap.to` is server-\n // authoritative); the quote boundary already failed-closed in that\n // case anyway, so this is purely belt-and-suspenders.\n if (wrapTx) {\n if (wrapTx.value !== quote.totalAmountIn) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step value ${wrapTx.value} does not match quote.totalAmountIn ${quote.totalAmountIn} (quote uuid: ${quote.uuid}).`,\n });\n }\n const expectedWrappedNative = recurringChainInfo.get(quote.chainId)?.wrappedNativeAddress;\n if (expectedWrappedNative && !isAddressEqual(wrapTx.to, expectedWrappedNative)) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step target ${wrapTx.to} does not match the published wrapped-native ${expectedWrappedNative} for chainId ${quote.chainId} (quote uuid: ${quote.uuid}).`,\n });\n }\n }\n\n // Approval target: for native input, the wrapped-native ERC-20 returned\n // by Markr in `wrap.to` (cross-checked above). For ERC-20 input, the\n // quote's `tokenIn`. Either way the spender is the RecurringSwaps router.\n const approvalTokenAddress = wrapTx?.to ?? quote.tokenIn;\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: approvalTokenAddress,\n });\n\n // Wrap leg comes straight from Markr — `wrap.to` is the chain wrapped-native\n // contract, `data` is `deposit()`, `value` is `totalAmountIn`. Gas is left\n // undefined: when batched the wallet handles atomic estimation; sequentially\n // the wrap is the first call so the wallet's own estimation fires the prompt.\n const wrapRequest: EvmTransactionRequest | undefined = wrapTx\n ? {\n chainId: chainIdHex,\n data: wrapTx.data,\n from: fromAddress,\n gas: undefined,\n to: wrapTx.to,\n value: wrapTx.value,\n ...maybe1559(gasSettings),\n }\n : undefined;\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n // One-click batch path: same-chain DCA, signer exposes `signBatch`, and at\n // least one leg precedes the swap (otherwise there's nothing to batch — we\n // sign the swap solo). The batch shape adapts to the recurring setup:\n // - native + needs approval: [wrap, approve, swap] (3 elements)\n // - native + allowance covers: [wrap, swap] (2 elements)\n // - ERC-20 + needs approval: [approve, swap] (2 elements)\n // - ERC-20 + allowance covers: swap solo (no batch)\n const batchPreSwap: EvmTransactionRequest[] = [];\n if (wrapRequest) batchPreSwap.push(wrapRequest);\n if (approvalRequest) batchPreSwap.push(approvalRequest);\n\n if (batchPreSwap.length > 0 && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the preceding leg(s) haven't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: undefined,\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [...batchPreSwap, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the sequential path below.\n }\n }\n\n // Sequential path — sign each preceding leg, await its receipt, then sign\n // the swap. Signature counters reflect the actual prompt count the user\n // will see (1 + wrap? + approval?).\n const requiredSignatures = 1 + batchPreSwap.length;\n let signatureCursor = 0;\n\n if (wrapRequest && wrapTx) {\n // Estimate gas for the wrap leg on the sequential path. On the batch\n // path we leave gas undefined and let the wallet do atomic estimation;\n // sequentially the wrap is a real first-tx prompt so it gets the same\n // treatment as the approval and swap legs (estimate + bps margin) for\n // wallets that don't auto-estimate. Read `to`/`data` off `wrapTx` (the\n // narrow `RecurringSwapTransaction` shape) rather than the wider\n // `EvmTransactionRequest` so the args are non-nullable.\n const wrapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: wrapTx.to, data: wrapTx.data, value: wrapTx.value },\n // No router ABI to decode against — wrap is a plain\n // `WAVAX.deposit{value}()`; built-in `Error(string)` / `Panic(uint256)`\n // are still decoded regardless of the ABI argument.\n [],\n 'Failed to estimate gas for recurring first-fill wrap transaction.',\n );\n const wrapRequestWithGas: EvmTransactionRequest = {\n ...wrapRequest,\n gas: applyFeeUnitsBpsMargin(wrapGasEstimate, gasSettings?.estimateGasMarginBps),\n };\n\n signatureCursor += 1;\n await signWrapAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: wrapRequestWithGas,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.WrapToken,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n if (approvalRequest) {\n signatureCursor += 1;\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: createOrderTx.to, data: createOrderTx.data, value: createOrderTx.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n signatureCursor += 1;\n const swapStep: TransferStepDetails = {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n/**\n * Signs a `WAVAX.deposit{value}()` wrap request, dispatches it, and waits for\n * the receipt. Mirrors {@link signApprovalAndAssertConfirmed} so the\n * sequential native path fails loudly if the wrap reverts on-chain (without\n * which the downstream approve would silently fail for \"insufficient WAVAX\").\n */\nasync function signWrapAndAssertConfirmed({\n client,\n evmSigner,\n request,\n step,\n}: {\n client: EvmSourceClient;\n evmSigner: EvmSigner;\n request: EvmTransactionRequest;\n step: TransferStepDetails;\n}): Promise<Hex> {\n const wrapTxHash = await evmSigner.sign(\n request,\n (signedTxHash) => client.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n const receipt = await client.waitForTransactionReceipt({ hash: wrapTxHash });\n\n if (receipt.status === 'reverted') {\n throw new SdkError(ErrorReason.NATIVE_WRAP_REVERTED, ErrorCode.TRANSACTION_REVERTED, {\n details: `Wrap tx reverted on-chain (tx hash: ${wrapTxHash}).`,\n });\n }\n\n return wrapTxHash;\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{ServiceType as e,TokenType as t,TransferSignatureReason as n}from"../../../constants.js";import{ErrorCode as r,ErrorReason as i,InvalidParamsError as a,SdkError as o}from"../../../errors.js";import{caip2ToEip155ChainId as s,caip2ToEip155HexChainId as c}from"../../../utils/caip.js";import{applyFeeUnitsBpsMargin as l,getEvmClientForChain as u,maybe1559 as d}from"../../_utils.js";import{estimateGasWithRevert as f}from"../../_evm-errors.js";import{buildErc20ApprovalRequest as p,signApprovalAndAssertConfirmed as m}from"../../_evm-approval.js";import{markrGetSpenderAddress as h}from"../_api.js";import{getMarkrSwapWrapperAbi as g}from"../_utils.js";import{markrListRecurringOrders as _,markrPrepareCancellation as v,markrPreparePause as y,markrPrepareUnpause as b,markrRecurringQuote as x,markrRecurringSwap as S}from"./_api.js";import{checkRecurringEligibility as C}from"./_eligibility.js";import{erc20Abi as w}from"viem";function T({apiOptions:e,appId:t,evmSigner:r,recurringChainInfo:i}){return{quote:n=>x(e,{...n,appId:t}),executeFirstFill:n=>E({...n,apiOptions:e,appId:t,evmSigner:r}),listOrders:t=>_(e,t),executeCancellation:t=>O({...t,signatureReason:n.CancelRecurringSwap,apiOptions:e,evmSigner:r,fetchCalldata:v}),executePause:t=>O({...t,signatureReason:n.PauseRecurringSwap,apiOptions:e,evmSigner:r,fetchCalldata:y}),executeUnpause:t=>O({...t,signatureReason:n.ResumeRecurringSwap,apiOptions:e,evmSigner:r,fetchCalldata:b}),checkEligibility:e=>C({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function E({apiOptions:e,appId:t,evmSigner:_,fallbackToDefaultOnBatchFailure:v,fromAddress:y,gasSettings:b,quote:x,signerContext:C,sourceChain:w}){let T=Math.floor(Date.now()/1e3);if(x.expiredAt<=T){let e=T-x.expiredAt;throw new a(i.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let E=s(w.chainId);if(E!==x.chainId)throw new a(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${w.chainId} resolves to ${E}, but quote.chainId=${x.chainId}.`);let D=u({chain:w}),O=c(w.chainId),{address:A}=await h(e,{chainId:x.chainId,crossChainSwap:!1,quoteId:x.uuid});if(!A)throw new o(i.CHAIN_NOT_SUPPORTED,r.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${w.chainId}.`});let j=await p({chainIdHex:O,client:D,gasSettings:b,owner:y,requiredAllowance:x.totalAmountIn,spender:A,token:x.tokenIn}),M=k({fromAddress:y,quote:x,sourceChain:w}),N=await S(e,{uuid:x.uuid,appId:t});if(j!==void 0&&typeof _.signBatch==`function`){let e={currentSignature:1,currentSignatureReason:n.ScheduleRecurringSwap,quote:M,requiredSignatures:1,signerContext:C},t={chainId:O,data:N.data,from:y,gas:void 0,to:N.to,value:N.value,...d(b)};try{let n=(await _.signBatch([j,t],e=>D.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!n)throw new o(`One-click batch signing returned no transaction hashes.`,r.SIGNING_FAILED);return{txHash:n}}catch(e){if(!v)throw e}}j&&await m({client:D,evmSigner:_,request:j,step:{currentSignature:1,currentSignatureReason:n.AllowanceApproval,quote:M,requiredSignatures:2,signerContext:C}});let P=await g(!1),F=await f(D,{account:y,to:N.to,data:N.data,value:N.value},P,`Failed to estimate gas for recurring first-fill swap transaction.`),I={chainId:O,data:N.data,from:y,gas:l(F,b?.estimateGasMarginBps),to:N.to,value:N.value,...d(b)},L={currentSignature:j?2:1,currentSignatureReason:n.ScheduleRecurringSwap,quote:M,requiredSignatures:j?2:1,signerContext:C};return{txHash:await _.sign(I,e=>D.sendRawTransaction({serializedTransaction:e}),L)}}const D={[n.PauseRecurringSwap]:`pause`,[n.ResumeRecurringSwap]:`resume`,[n.CancelRecurringSwap]:`cancel`};async function O({signatureReason:e,address:t,apiOptions:n,evmSigner:r,fetchCalldata:i,gasSettings:a,orderId:o,signerContext:p,sourceChain:m}){let h=u({chain:m}),g=s(m.chainId),_=c(m.chainId),v=await i(n,{orderId:o,address:t,chainId:g}),y=await f(h,{account:t,to:v.to,data:v.data,value:v.value},w,`Failed to estimate gas for recurring ${D[e]} transaction.`),b={chainId:_,data:v.data,from:t,gas:l(y,a?.estimateGasMarginBps),to:v.to,value:v.value,...d(a)},x={currentSignature:1,currentSignatureReason:e,quote:A({address:t,signatureReason:e,orderId:o,sourceChain:m}),requiredSignatures:1,signerContext:p};return{txHash:await r.sign(b,e=>h.sendRawTransaction({serializedTransaction:e}),x)}}function k({fromAddress:n,quote:r,sourceChain:i}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:r.amount,amountOut:r.amountOut,assetIn:{type:t.ERC20,address:r.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:t.ERC20,address:r.tokenOut,name:``,symbol:``,decimals:0},expiresAt:r.expiredAt,fees:[],fromAddress:n,id:r.uuid,partnerFeeBps:null,serviceType:e.MARKR,slippageBps:r.recommendedSlippage,sourceChain:i,targetChain:i,toAddress:n}}function A({signatureReason:t,address:n,orderId:r,sourceChain:i}){let a=D[t];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:j(),assetOut:j(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:e.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function j(){return{type:t.NATIVE,name:``,symbol:``,decimals:0}}export{T as createRecurringNamespace};
1
+ import{ERC_ZERO_ADDRESS as e,ServiceType as t,TokenType as n,TransferSignatureReason as r}from"../../../constants.js";import{ErrorCode as i,ErrorReason as a,InvalidParamsError as o,SdkError as s}from"../../../errors.js";import{caip2ToEip155ChainId as c,caip2ToEip155HexChainId as l}from"../../../utils/caip.js";import{applyFeeUnitsBpsMargin as u,getEvmClientForChain as d,maybe1559 as f}from"../../_utils.js";import{estimateGasWithRevert as p}from"../../_evm-errors.js";import{buildErc20ApprovalRequest as m,signApprovalAndAssertConfirmed as h}from"../../_evm-approval.js";import{markrGetSpenderAddress as g}from"../_api.js";import{getMarkrSwapWrapperAbi as _}from"../_utils.js";import{markrListRecurringOrders as v,markrPrepareCancellation as y,markrPreparePause as b,markrPrepareUnpause as x,markrRecurringQuote as S,markrRecurringSwap as C}from"./_api.js";import{checkRecurringEligibility as w}from"./_eligibility.js";import{erc20Abi as T,isAddressEqual as E}from"viem";function D({apiOptions:e,appId:t,evmSigner:n,recurringChainInfo:i}){return{quote:n=>O({...n,apiOptions:e,appId:t,recurringChainInfo:i}),executeFirstFill:r=>k({...r,apiOptions:e,appId:t,evmSigner:n,recurringChainInfo:i}),listOrders:t=>v(e,t),executeCancellation:t=>M({...t,signatureReason:r.CancelRecurringSwap,apiOptions:e,evmSigner:n,fetchCalldata:y}),executePause:t=>M({...t,signatureReason:r.PauseRecurringSwap,apiOptions:e,evmSigner:n,fetchCalldata:b}),executeUnpause:t=>M({...t,signatureReason:r.ResumeRecurringSwap,apiOptions:e,evmSigner:n,fetchCalldata:x}),checkEligibility:e=>w({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function O({apiOptions:e,appId:t,recurringChainInfo:n,...r}){if(E(r.tokenIn,`0x0000000000000000000000000000000000000000`)&&!n.get(r.chainId)?.wrappedNativeAddress)throw new o(a.CHAIN_NOT_SUPPORTED,`No wrapped-native ERC-20 address known for EVM chainId ${r.chainId}. Native-input recurring swaps require Markr to publish \`wrapped_token\` for the chain in \`/info/chains\`.`);return S(e,{...r,appId:t})}async function k({apiOptions:t,appId:n,evmSigner:v,fallbackToDefaultOnBatchFailure:y,fromAddress:b,gasSettings:x,quote:S,recurringChainInfo:w,signerContext:T,sourceChain:D}){let O=Math.floor(Date.now()/1e3);if(S.expiredAt<=O){let e=O-S.expiredAt;throw new o(a.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let k=c(D.chainId);if(k!==S.chainId)throw new o(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${D.chainId} resolves to ${k}, but quote.chainId=${S.chainId}.`);let j=d({chain:D}),M=l(D.chainId),P=E(S.tokenIn,e),{address:F}=await g(t,{chainId:S.chainId,crossChainSwap:!1,quoteId:S.uuid});if(!F)throw new s(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${D.chainId}.`});let I=await C(t,{uuid:S.uuid,appId:n}),L=I.find(e=>e.type===`wrap`),R=I.find(e=>e.type===`createOrder`);if(!R)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Missing createOrder step (quote uuid: ${S.uuid}).`});if(P&&!L)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Native-input quote returned no wrap step (quote uuid: ${S.uuid}).`});if(!P&&L)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`ERC-20 input quote returned a wrap step (quote uuid: ${S.uuid}, tokenIn: ${S.tokenIn}).`});if(L){if(L.value!==S.totalAmountIn)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Wrap step value ${L.value} does not match quote.totalAmountIn ${S.totalAmountIn} (quote uuid: ${S.uuid}).`});let e=w.get(S.chainId)?.wrappedNativeAddress;if(e&&!E(L.to,e))throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Wrap step target ${L.to} does not match the published wrapped-native ${e} for chainId ${S.chainId} (quote uuid: ${S.uuid}).`})}let z=L?.to??S.tokenIn,B=await m({chainIdHex:M,client:j,gasSettings:x,owner:b,requiredAllowance:S.totalAmountIn,spender:F,token:z}),V=L?{chainId:M,data:L.data,from:b,gas:void 0,to:L.to,value:L.value,...f(x)}:void 0,H=N({fromAddress:b,quote:S,sourceChain:D}),U=[];if(V&&U.push(V),B&&U.push(B),U.length>0&&typeof v.signBatch==`function`){let e={currentSignature:1,currentSignatureReason:r.ScheduleRecurringSwap,quote:H,requiredSignatures:1,signerContext:T},t={chainId:M,data:R.data,from:b,gas:void 0,to:R.to,value:R.value,...f(x)};try{let n=(await v.signBatch([...U,t],e=>j.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!n)throw new s(`One-click batch signing returned no transaction hashes.`,i.SIGNING_FAILED);return{txHash:n}}catch(e){if(!y)throw e}}let W=1+U.length,G=0;if(V&&L){let e=await p(j,{account:b,to:L.to,data:L.data,value:L.value},[],`Failed to estimate gas for recurring first-fill wrap transaction.`),t={...V,gas:u(e,x?.estimateGasMarginBps)};G+=1,await A({client:j,evmSigner:v,request:t,step:{currentSignature:G,currentSignatureReason:r.WrapToken,quote:H,requiredSignatures:W,signerContext:T}})}B&&(G+=1,await h({client:j,evmSigner:v,request:B,step:{currentSignature:G,currentSignatureReason:r.AllowanceApproval,quote:H,requiredSignatures:W,signerContext:T}}));let K=await _(!1),q=await p(j,{account:b,to:R.to,data:R.data,value:R.value},K,`Failed to estimate gas for recurring first-fill swap transaction.`),J={chainId:M,data:R.data,from:b,gas:u(q,x?.estimateGasMarginBps),to:R.to,value:R.value,...f(x)};G+=1;let Y={currentSignature:G,currentSignatureReason:r.ScheduleRecurringSwap,quote:H,requiredSignatures:W,signerContext:T};return{txHash:await v.sign(J,e=>j.sendRawTransaction({serializedTransaction:e}),Y)}}async function A({client:e,evmSigner:t,request:n,step:r}){let o=await t.sign(n,t=>e.sendRawTransaction({serializedTransaction:t}),r);if((await e.waitForTransactionReceipt({hash:o})).status===`reverted`)throw new s(a.NATIVE_WRAP_REVERTED,i.TRANSACTION_REVERTED,{details:`Wrap tx reverted on-chain (tx hash: ${o}).`});return o}const j={[r.PauseRecurringSwap]:`pause`,[r.ResumeRecurringSwap]:`resume`,[r.CancelRecurringSwap]:`cancel`};async function M({signatureReason:e,address:t,apiOptions:n,evmSigner:r,fetchCalldata:i,gasSettings:a,orderId:o,signerContext:s,sourceChain:m}){let h=d({chain:m}),g=c(m.chainId),_=l(m.chainId),v=await i(n,{orderId:o,address:t,chainId:g}),y=await p(h,{account:t,to:v.to,data:v.data,value:v.value},T,`Failed to estimate gas for recurring ${j[e]} transaction.`),b={chainId:_,data:v.data,from:t,gas:u(y,a?.estimateGasMarginBps),to:v.to,value:v.value,...f(a)},x={currentSignature:1,currentSignatureReason:e,quote:P({address:t,signatureReason:e,orderId:o,sourceChain:m}),requiredSignatures:1,signerContext:s};return{txHash:await r.sign(b,e=>h.sendRawTransaction({serializedTransaction:e}),x)}}function N({fromAddress:e,quote:r,sourceChain:i}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:r.amount,amountOut:r.amountOut,assetIn:{type:n.ERC20,address:r.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:n.ERC20,address:r.tokenOut,name:``,symbol:``,decimals:0},expiresAt:r.expiredAt,fees:[],fromAddress:e,id:r.uuid,partnerFeeBps:null,serviceType:t.MARKR,slippageBps:r.recommendedSlippage,sourceChain:i,targetChain:i,toAddress:e}}function P({signatureReason:e,address:n,orderId:r,sourceChain:i}){let a=j[e];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:F(),assetOut:F(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:t.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function F(){return{type:n.NATIVE,name:``,symbol:``,decimals:0}}export{D as createRecurringNamespace};
2
2
  //# sourceMappingURL=_namespace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_namespace.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi } from 'viem';\nimport { ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => markrRecurringQuote(apiOptions, { ...props, appId }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: quote.tokenIn,\n });\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n const swap = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n // One-click batch path: same-chain DCA, approval required, signer exposes\n // `signBatch`. Matches `_executeEvmTransfer`'s eligibility check (recurring\n // is always same-chain so the cross-chain check there collapses to true).\n if (approvalRequest !== undefined && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the approval hasn't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [approvalRequest, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the two-signature path below.\n }\n }\n\n if (approvalRequest) {\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures: 2,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: swap.to, data: swap.data, value: swap.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n const swapStep: TransferStepDetails = {\n currentSignature: approvalRequest ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: approvalRequest ? 2 : 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_namespace.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi, isAddressEqual } from 'viem';\nimport { ERC_ZERO_ADDRESS, ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest, Hex } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport type { EvmSourceClient } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringNamespaceQuoteParams,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => quoteImpl({ ...props, apiOptions, appId, recurringChainInfo }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner, recurringChainInfo }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Quote — native input (`tokenIn === 0x0…`) is passed through to Markr\n// verbatim (the recurring API accepts the zero address as `tokenIn`). The\n// chain's wrapped-native address is read off the cached chain info (sourced\n// from `/info/chains[].wrapped_token`); the SDK only fails fast at this\n// boundary when Markr hasn't published one for the chain — we'd be issuing\n// a quote we couldn't honor.\n// ---------------------------------------------------------------------------\n\ninterface QuoteImplParams extends RecurringNamespaceQuoteParams {\n apiOptions: ApiOptions;\n appId: string;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function quoteImpl({\n apiOptions,\n appId,\n recurringChainInfo,\n ...quoteParams\n}: QuoteImplParams): Promise<RecurringQuoteResponse> {\n const isNativeInput = isAddressEqual(quoteParams.tokenIn, ERC_ZERO_ADDRESS);\n\n if (isNativeInput && !recurringChainInfo.get(quoteParams.chainId)?.wrappedNativeAddress) {\n throw new InvalidParamsError(\n ErrorReason.CHAIN_NOT_SUPPORTED,\n `No wrapped-native ERC-20 address known for EVM chainId ${quoteParams.chainId}. ` +\n 'Native-input recurring swaps require Markr to publish `wrapped_token` for the chain in `/info/chains`.',\n );\n }\n\n return markrRecurringQuote(apiOptions, { ...quoteParams, appId });\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n recurringChainInfo,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const isNativeInput = isAddressEqual(quote.tokenIn, ERC_ZERO_ADDRESS);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n // Fetch the ordered transaction array from Markr's `/recurring/swap`:\n // - ERC-20 `tokenIn`: `[createOrder]` (1 element).\n // - Native `tokenIn` (`0x0…`): `[wrap, createOrder]` (2 elements).\n // The wrap's `to` is the wrapped-native ERC-20 we'll then approve against\n // (Markr does not return an approval entry — the SDK inserts that step).\n const recurringSwapTxs = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n const wrapTx = recurringSwapTxs.find((tx) => tx.type === 'wrap');\n const createOrderTx = recurringSwapTxs.find((tx) => tx.type === 'createOrder');\n\n if (!createOrderTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Missing createOrder step (quote uuid: ${quote.uuid}).`,\n });\n }\n\n // Cross-check: native input must come back with a wrap leg, and an ERC-20\n // input must not. If Markr disagrees with the cached quote's `tokenIn`,\n // bail rather than silently signing a mismatched flow (e.g. broadcasting\n // a wrap when the user thought they were spending ERC-20, or skipping a\n // wrap when the user expected to fund the schedule with native).\n if (isNativeInput && !wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Native-input quote returned no wrap step (quote uuid: ${quote.uuid}).`,\n });\n }\n if (!isNativeInput && wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `ERC-20 input quote returned a wrap step (quote uuid: ${quote.uuid}, tokenIn: ${quote.tokenIn}).`,\n });\n }\n\n // Defense-in-depth on the wrap leg before we hand it to the wallet:\n // - `wrap.value` must equal `quote.totalAmountIn` — that's what funds the\n // full schedule; a smaller value would under-fund subsequent fills, a\n // larger one would silently overcharge the user.\n // - `wrap.to` must match the chain's published wrapped-native (from\n // `/info/chains[].wrapped_token`) when one is known. Cross-check guards\n // against a misrouted approval — we're about to grant `totalAmountIn`\n // allowance to whatever `wrap.to` points at. When the chain entry has\n // no published wrapped-native, defer to Markr (`wrap.to` is server-\n // authoritative); the quote boundary already failed-closed in that\n // case anyway, so this is purely belt-and-suspenders.\n if (wrapTx) {\n if (wrapTx.value !== quote.totalAmountIn) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step value ${wrapTx.value} does not match quote.totalAmountIn ${quote.totalAmountIn} (quote uuid: ${quote.uuid}).`,\n });\n }\n const expectedWrappedNative = recurringChainInfo.get(quote.chainId)?.wrappedNativeAddress;\n if (expectedWrappedNative && !isAddressEqual(wrapTx.to, expectedWrappedNative)) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step target ${wrapTx.to} does not match the published wrapped-native ${expectedWrappedNative} for chainId ${quote.chainId} (quote uuid: ${quote.uuid}).`,\n });\n }\n }\n\n // Approval target: for native input, the wrapped-native ERC-20 returned\n // by Markr in `wrap.to` (cross-checked above). For ERC-20 input, the\n // quote's `tokenIn`. Either way the spender is the RecurringSwaps router.\n const approvalTokenAddress = wrapTx?.to ?? quote.tokenIn;\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: approvalTokenAddress,\n });\n\n // Wrap leg comes straight from Markr — `wrap.to` is the chain wrapped-native\n // contract, `data` is `deposit()`, `value` is `totalAmountIn`. Gas is left\n // undefined: when batched the wallet handles atomic estimation; sequentially\n // the wrap is the first call so the wallet's own estimation fires the prompt.\n const wrapRequest: EvmTransactionRequest | undefined = wrapTx\n ? {\n chainId: chainIdHex,\n data: wrapTx.data,\n from: fromAddress,\n gas: undefined,\n to: wrapTx.to,\n value: wrapTx.value,\n ...maybe1559(gasSettings),\n }\n : undefined;\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n // One-click batch path: same-chain DCA, signer exposes `signBatch`, and at\n // least one leg precedes the swap (otherwise there's nothing to batch — we\n // sign the swap solo). The batch shape adapts to the recurring setup:\n // - native + needs approval: [wrap, approve, swap] (3 elements)\n // - native + allowance covers: [wrap, swap] (2 elements)\n // - ERC-20 + needs approval: [approve, swap] (2 elements)\n // - ERC-20 + allowance covers: swap solo (no batch)\n const batchPreSwap: EvmTransactionRequest[] = [];\n if (wrapRequest) batchPreSwap.push(wrapRequest);\n if (approvalRequest) batchPreSwap.push(approvalRequest);\n\n if (batchPreSwap.length > 0 && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the preceding leg(s) haven't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: undefined,\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [...batchPreSwap, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the sequential path below.\n }\n }\n\n // Sequential path — sign each preceding leg, await its receipt, then sign\n // the swap. Signature counters reflect the actual prompt count the user\n // will see (1 + wrap? + approval?).\n const requiredSignatures = 1 + batchPreSwap.length;\n let signatureCursor = 0;\n\n if (wrapRequest && wrapTx) {\n // Estimate gas for the wrap leg on the sequential path. On the batch\n // path we leave gas undefined and let the wallet do atomic estimation;\n // sequentially the wrap is a real first-tx prompt so it gets the same\n // treatment as the approval and swap legs (estimate + bps margin) for\n // wallets that don't auto-estimate. Read `to`/`data` off `wrapTx` (the\n // narrow `RecurringSwapTransaction` shape) rather than the wider\n // `EvmTransactionRequest` so the args are non-nullable.\n const wrapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: wrapTx.to, data: wrapTx.data, value: wrapTx.value },\n // No router ABI to decode against — wrap is a plain\n // `WAVAX.deposit{value}()`; built-in `Error(string)` / `Panic(uint256)`\n // are still decoded regardless of the ABI argument.\n [],\n 'Failed to estimate gas for recurring first-fill wrap transaction.',\n );\n const wrapRequestWithGas: EvmTransactionRequest = {\n ...wrapRequest,\n gas: applyFeeUnitsBpsMargin(wrapGasEstimate, gasSettings?.estimateGasMarginBps),\n };\n\n signatureCursor += 1;\n await signWrapAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: wrapRequestWithGas,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.WrapToken,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n if (approvalRequest) {\n signatureCursor += 1;\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: createOrderTx.to, data: createOrderTx.data, value: createOrderTx.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n signatureCursor += 1;\n const swapStep: TransferStepDetails = {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n/**\n * Signs a `WAVAX.deposit{value}()` wrap request, dispatches it, and waits for\n * the receipt. Mirrors {@link signApprovalAndAssertConfirmed} so the\n * sequential native path fails loudly if the wrap reverts on-chain (without\n * which the downstream approve would silently fail for \"insufficient WAVAX\").\n */\nasync function signWrapAndAssertConfirmed({\n client,\n evmSigner,\n request,\n step,\n}: {\n client: EvmSourceClient;\n evmSigner: EvmSigner;\n request: EvmTransactionRequest;\n step: TransferStepDetails;\n}): Promise<Hex> {\n const wrapTxHash = await evmSigner.sign(\n request,\n (signedTxHash) => client.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n const receipt = await client.waitForTransactionReceipt({ hash: wrapTxHash });\n\n if (receipt.status === 'reverted') {\n throw new SdkError(ErrorReason.NATIVE_WRAP_REVERTED, ErrorCode.TRANSACTION_REVERTED, {\n details: `Wrap tx reverted on-chain (tx hash: ${wrapTxHash}).`,\n });\n }\n\n return wrapTxHash;\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`./types.cjs`),t=require(`../../service-schemas.cjs`);let n=require(`zod`);const r=/^0x[0-9a-fA-F]{64}$/,i=n.z.enum(e.RECURRING_FREQUENCY_UNITS),a=n.z.object({unit:i,value:n.z.number().int().min(1)}),o=n.z.enum(Object.values(e.RecurringOrderStatus)),s=n.z.object({executionIndex:n.z.number().int().nonnegative(),reasons:n.z.array(n.z.string()),tryCount:n.z.number().int().nonnegative(),failedAt:n.z.number().int().nonnegative()}),c=n.z.string().regex(r,`Invalid recurring order id (expected 0x-prefixed bytes32)`).transform(e=>e),l=n.z.object({orderId:c,owner:t.EvmAddressSchema,chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),executedOrders:n.z.number().int().nonnegative(),remainingOrders:n.z.number().int().nonnegative().nullish().transform(e=>e??null),frequency:a,totalAmountIn:n.z.coerce.bigint().nonnegative(),tryCount:n.z.number().int().nonnegative(),failures:n.z.array(s),status:o,createdAt:n.z.number().int().nonnegative(),nextExecutionAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null),cancelledAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null)}),u=n.z.object({type:n.z.enum([`gas`,`recurring`,`protocol`,`bridge`,`slippage`,`swap`,`other`]).or(n.z.string()),name:n.z.string(),amount:n.z.coerce.bigint().nonnegative(),token:n.z.object({chainId:n.z.coerce.number().int().nonnegative(),address:t.EvmAddressSchema}),extra:n.z.union([n.z.boolean(),n.z.record(n.z.string(),n.z.unknown())]).optional()}),d=n.z.object({uuid:n.z.uuid(),chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),frequency:a,intervalSeconds:n.z.number().int().nonnegative(),totalAmountIn:n.z.coerce.bigint().nonnegative(),amountOut:n.z.coerce.bigint().nonnegative(),minAmountOut:n.z.coerce.bigint().nonnegative(),fees:n.z.array(u),recommendedSlippage:n.z.number().int().nonnegative(),expiredAt:n.z.number().int().nonnegative()}),f=n.z.object({address:t.EvmAddressSchema,count:n.z.number().int().nonnegative(),orders:n.z.array(l)});exports.ListRecurringOrdersResponseSchema=f,exports.RecurringQuoteResponseSchema=d;
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`./types.cjs`),t=require(`../../service-schemas.cjs`);let n=require(`zod`);const r=/^0x[0-9a-fA-F]{64}$/,i=n.z.enum(e.RECURRING_FREQUENCY_UNITS),a=n.z.object({unit:i,value:n.z.number().int().min(1)}),o=n.z.enum(Object.values(e.RecurringOrderStatus)),s=n.z.object({executionIndex:n.z.number().int().nonnegative(),reasons:n.z.array(n.z.string()),tryCount:n.z.number().int().nonnegative(),failedAt:n.z.number().int().nonnegative()}),c=n.z.object({type:n.z.enum([`wrap`,`createOrder`]),to:t.EvmAddressSchema,data:t.HexSchema,value:n.z.coerce.bigint().nonnegative()}),l=n.z.array(c),u=n.z.string().regex(r,`Invalid recurring order id (expected 0x-prefixed bytes32)`).transform(e=>e),d=n.z.object({orderId:u,owner:t.EvmAddressSchema,chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),executedOrders:n.z.number().int().nonnegative(),remainingOrders:n.z.number().int().nonnegative().nullish().transform(e=>e??null),frequency:a,totalAmountIn:n.z.coerce.bigint().nonnegative(),tryCount:n.z.number().int().nonnegative(),failures:n.z.array(s),status:o,createdAt:n.z.number().int().nonnegative(),nextExecutionAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null),cancelledAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null)}),f=n.z.object({type:n.z.enum([`gas`,`recurring`,`protocol`,`bridge`,`slippage`,`swap`,`other`]).or(n.z.string()),name:n.z.string(),amount:n.z.coerce.bigint().nonnegative(),token:n.z.object({chainId:n.z.coerce.number().int().nonnegative(),address:t.EvmAddressSchema}),extra:n.z.union([n.z.boolean(),n.z.record(n.z.string(),n.z.unknown())]).optional()}),p=n.z.object({uuid:n.z.uuid(),chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),frequency:a,intervalSeconds:n.z.number().int().nonnegative(),totalAmountIn:n.z.coerce.bigint().nonnegative(),amountOut:n.z.coerce.bigint().nonnegative(),minAmountOut:n.z.coerce.bigint().nonnegative(),fees:n.z.array(f),recommendedSlippage:n.z.number().int().nonnegative(),expiredAt:n.z.number().int().nonnegative()}),m=n.z.object({address:t.EvmAddressSchema,count:n.z.number().int().nonnegative(),orders:n.z.array(d)});exports.ListRecurringOrdersResponseSchema=m,exports.RecurringQuoteResponseSchema=p,exports.RecurringSwapResponseSchema=l;
2
2
  //# sourceMappingURL=_schema.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_schema.cjs","names":["z","RECURRING_FREQUENCY_UNITS","RecurringOrderStatus","EvmAddressSchema"],"sources":["../../../../src/transfer-service/markr/recurring/_schema.ts"],"sourcesContent":["import { z } from 'zod';\nimport { EvmAddressSchema } from '../../service-schemas';\nimport {\n RECURRING_FREQUENCY_UNITS,\n RecurringOrderStatus,\n type ListRecurringOrdersResponse,\n type RecurringFrequency,\n type RecurringFrequencyUnit,\n type RecurringOrder,\n type RecurringOrderFailure,\n type RecurringQuoteResponse,\n} from './types';\n\nconst ORDER_ID_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\nexport const RecurringFrequencyUnitSchema: z.ZodType<RecurringFrequencyUnit> = z.enum(RECURRING_FREQUENCY_UNITS);\n\nexport const RecurringFrequencySchema: z.ZodType<RecurringFrequency> = z.object({\n unit: RecurringFrequencyUnitSchema,\n value: z.number().int().min(1),\n});\n\n/**\n * Closed enum — see {@link RecurringOrderStatus}. Unknown server-side values\n * (e.g. a hypothetical `'expired'`) will fail parsing loudly, which gates\n * UI behavior on an SDK update rather than silently surfacing an unhandled\n * status to the consumer.\n */\nexport const RecurringOrderStatusSchema: z.ZodType<RecurringOrderStatus> = z.enum(\n Object.values(RecurringOrderStatus) as [RecurringOrderStatus, ...RecurringOrderStatus[]],\n);\n\nexport const RecurringOrderFailureSchema: z.ZodType<RecurringOrderFailure> = z.object({\n // `nonnegative` (not `positive`) — Markr documents `executionIndex` as\n // 1-based today, but forward-compat with a future setup-time failure\n // emitting index `0` costs nothing and matches the same brittleness fix\n // applied to the status / fee-type enums.\n executionIndex: z.number().int().nonnegative(),\n reasons: z.array(z.string()),\n tryCount: z.number().int().nonnegative(),\n failedAt: z.number().int().nonnegative(),\n});\n\n/**\n * `0x`-prefixed bytes32 hex. Use `.transform()` to widen `string` into the\n * template-literal type that `RecurringOrder.orderId` declares — mirrors the\n * `EvmAddressSchema` pattern from `service-schemas.ts`.\n */\nconst OrderIdSchema: z.ZodType<`0x${string}`> = z\n .string()\n .regex(ORDER_ID_REGEX, 'Invalid recurring order id (expected 0x-prefixed bytes32)')\n .transform((value) => value as `0x${string}`);\n\n/**\n * Schema for a single `RecurringOrder` element as returned by Markr's\n * `/recurring/orders` (list) and `/recurring/orders/{orderId}/cancel`\n * endpoints.\n */\nexport const RecurringOrderSchema: z.ZodType<RecurringOrder> = z.object({\n orderId: OrderIdSchema,\n owner: EvmAddressSchema,\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n executedOrders: z.number().int().nonnegative(),\n // `null` (or omitted) on unlimited schedules per the Markr OpenAPI spec —\n // `numberOfOrders: -1` schedules have no finite remainder to report. Finite\n // schedules carry `numberOfOrders - executedOrders` as a non-negative int.\n // `.nullish()` accepts both `null` and `undefined`; we normalize to `null`\n // by coercing `undefined` via a default transform so consumers can use a\n // simple `if (order.remainingOrders === null)` check instead of also\n // guarding for `undefined`.\n remainingOrders: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n frequency: RecurringFrequencySchema,\n totalAmountIn: z.coerce.bigint().nonnegative(),\n tryCount: z.number().int().nonnegative(),\n failures: z.array(RecurringOrderFailureSchema),\n status: RecurringOrderStatusSchema,\n createdAt: z.number().int().nonnegative(),\n // OpenAPI marks `nextExecutionAt` as optional + nullable — accept all\n // three wire shapes (number / null / omitted) and normalize to\n // `number | null` so consumers can use a single `=== null` check.\n // Same pattern as `remainingOrders` above.\n nextExecutionAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n // OpenAPI marks `cancelledAt` as optional + nullable; populated only when\n // `status === 'cancelled'`. Normalize to `number | null` (always present\n // in the parsed shape) for the same consumer-ergonomics reason as\n // `nextExecutionAt` / `remainingOrders`.\n cancelledAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n});\n\nconst RecurringQuoteFeeSchema = z.object({\n // Tolerant of unknown fee categories (forward-compat). Unlike\n // `RecurringOrderStatusSchema` (closed enum — see comment there), a new\n // fee category from Markr is safe to render as \"Other fee\" instead of\n // bricking parsing on already-shipped clients.\n type: z.enum(['gas', 'recurring', 'protocol', 'bridge', 'slippage', 'swap', 'other']).or(z.string()),\n name: z.string(),\n amount: z.coerce.bigint().nonnegative(),\n token: z.object({\n chainId: z.coerce.number().int().nonnegative(),\n address: EvmAddressSchema,\n }),\n // Docs: `extra: boolean or object` — accept both. See the equivalent\n // widening on the one-shot quote schema in `markr/_schema.ts`.\n extra: z.union([z.boolean(), z.record(z.string(), z.unknown())]).optional(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/quote` endpoint.\n */\nexport const RecurringQuoteResponseSchema: z.ZodType<RecurringQuoteResponse> = z.object({\n uuid: z.uuid(),\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n frequency: RecurringFrequencySchema,\n intervalSeconds: z.number().int().nonnegative(),\n totalAmountIn: z.coerce.bigint().nonnegative(),\n amountOut: z.coerce.bigint().nonnegative(),\n minAmountOut: z.coerce.bigint().nonnegative(),\n fees: z.array(RecurringQuoteFeeSchema),\n recommendedSlippage: z.number().int().nonnegative(),\n expiredAt: z.number().int().nonnegative(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/orders` (list) endpoint.\n */\nexport const ListRecurringOrdersResponseSchema: z.ZodType<ListRecurringOrdersResponse> = z.object({\n address: EvmAddressSchema,\n count: z.number().int().nonnegative(),\n orders: z.array(RecurringOrderSchema),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"_schema.cjs","names":["z","RECURRING_FREQUENCY_UNITS","RecurringOrderStatus","EvmAddressSchema","HexSchema"],"sources":["../../../../src/transfer-service/markr/recurring/_schema.ts"],"sourcesContent":["import { z } from 'zod';\nimport { EvmAddressSchema, HexSchema } from '../../service-schemas';\nimport {\n RECURRING_FREQUENCY_UNITS,\n RecurringOrderStatus,\n type ListRecurringOrdersResponse,\n type RecurringFrequency,\n type RecurringFrequencyUnit,\n type RecurringOrder,\n type RecurringOrderFailure,\n type RecurringQuoteResponse,\n type RecurringSwapResponse,\n type RecurringSwapTransaction,\n} from './types';\n\nconst ORDER_ID_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\nexport const RecurringFrequencyUnitSchema: z.ZodType<RecurringFrequencyUnit> = z.enum(RECURRING_FREQUENCY_UNITS);\n\nexport const RecurringFrequencySchema: z.ZodType<RecurringFrequency> = z.object({\n unit: RecurringFrequencyUnitSchema,\n value: z.number().int().min(1),\n});\n\n/**\n * Closed enum — see {@link RecurringOrderStatus}. Unknown server-side values\n * (e.g. a hypothetical `'expired'`) will fail parsing loudly, which gates\n * UI behavior on an SDK update rather than silently surfacing an unhandled\n * status to the consumer.\n */\nexport const RecurringOrderStatusSchema: z.ZodType<RecurringOrderStatus> = z.enum(\n Object.values(RecurringOrderStatus) as [RecurringOrderStatus, ...RecurringOrderStatus[]],\n);\n\nexport const RecurringOrderFailureSchema: z.ZodType<RecurringOrderFailure> = z.object({\n // `nonnegative` (not `positive`) — Markr documents `executionIndex` as\n // 1-based today, but forward-compat with a future setup-time failure\n // emitting index `0` costs nothing and matches the same brittleness fix\n // applied to the status / fee-type enums.\n executionIndex: z.number().int().nonnegative(),\n reasons: z.array(z.string()),\n tryCount: z.number().int().nonnegative(),\n failedAt: z.number().int().nonnegative(),\n});\n\n/**\n * Schema for a single step in {@link RecurringSwapResponse}. Markr's\n * `/recurring/swap` doc documents two `type` values; we keep this as a\n * closed enum so an unrecognized step (e.g. a hypothetical future\n * `'approve'`) fails parsing loudly — the SDK builds the approval itself\n * and a server-side change to that contract should gate on an SDK update.\n */\nexport const RecurringSwapTransactionSchema: z.ZodType<RecurringSwapTransaction> = z.object({\n type: z.enum(['wrap', 'createOrder']),\n to: EvmAddressSchema,\n data: HexSchema,\n value: z.coerce.bigint().nonnegative(),\n});\n\n/**\n * Response schema for Markr's `/recurring/swap`. Always an array, ordered;\n * the consumer signs each entry in array order. See\n * {@link RecurringSwapResponse}.\n */\nexport const RecurringSwapResponseSchema: z.ZodType<RecurringSwapResponse> = z.array(RecurringSwapTransactionSchema);\n\n/**\n * `0x`-prefixed bytes32 hex. Use `.transform()` to widen `string` into the\n * template-literal type that `RecurringOrder.orderId` declares — mirrors the\n * `EvmAddressSchema` pattern from `service-schemas.ts`.\n */\nconst OrderIdSchema: z.ZodType<`0x${string}`> = z\n .string()\n .regex(ORDER_ID_REGEX, 'Invalid recurring order id (expected 0x-prefixed bytes32)')\n .transform((value) => value as `0x${string}`);\n\n/**\n * Schema for a single `RecurringOrder` element as returned by Markr's\n * `/recurring/orders` (list) and `/recurring/orders/{orderId}/cancel`\n * endpoints.\n */\nexport const RecurringOrderSchema: z.ZodType<RecurringOrder> = z.object({\n orderId: OrderIdSchema,\n owner: EvmAddressSchema,\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n executedOrders: z.number().int().nonnegative(),\n // `null` (or omitted) on unlimited schedules per the Markr OpenAPI spec —\n // `numberOfOrders: -1` schedules have no finite remainder to report. Finite\n // schedules carry `numberOfOrders - executedOrders` as a non-negative int.\n // `.nullish()` accepts both `null` and `undefined`; we normalize to `null`\n // by coercing `undefined` via a default transform so consumers can use a\n // simple `if (order.remainingOrders === null)` check instead of also\n // guarding for `undefined`.\n remainingOrders: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n frequency: RecurringFrequencySchema,\n totalAmountIn: z.coerce.bigint().nonnegative(),\n tryCount: z.number().int().nonnegative(),\n failures: z.array(RecurringOrderFailureSchema),\n status: RecurringOrderStatusSchema,\n createdAt: z.number().int().nonnegative(),\n // OpenAPI marks `nextExecutionAt` as optional + nullable — accept all\n // three wire shapes (number / null / omitted) and normalize to\n // `number | null` so consumers can use a single `=== null` check.\n // Same pattern as `remainingOrders` above.\n nextExecutionAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n // OpenAPI marks `cancelledAt` as optional + nullable; populated only when\n // `status === 'cancelled'`. Normalize to `number | null` (always present\n // in the parsed shape) for the same consumer-ergonomics reason as\n // `nextExecutionAt` / `remainingOrders`.\n cancelledAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n});\n\nconst RecurringQuoteFeeSchema = z.object({\n // Tolerant of unknown fee categories (forward-compat). Unlike\n // `RecurringOrderStatusSchema` (closed enum — see comment there), a new\n // fee category from Markr is safe to render as \"Other fee\" instead of\n // bricking parsing on already-shipped clients.\n type: z.enum(['gas', 'recurring', 'protocol', 'bridge', 'slippage', 'swap', 'other']).or(z.string()),\n name: z.string(),\n amount: z.coerce.bigint().nonnegative(),\n token: z.object({\n chainId: z.coerce.number().int().nonnegative(),\n address: EvmAddressSchema,\n }),\n // Docs: `extra: boolean or object` — accept both. See the equivalent\n // widening on the one-shot quote schema in `markr/_schema.ts`.\n extra: z.union([z.boolean(), z.record(z.string(), z.unknown())]).optional(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/quote` endpoint.\n */\nexport const RecurringQuoteResponseSchema: z.ZodType<RecurringQuoteResponse> = z.object({\n uuid: z.uuid(),\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n frequency: RecurringFrequencySchema,\n intervalSeconds: z.number().int().nonnegative(),\n totalAmountIn: z.coerce.bigint().nonnegative(),\n amountOut: z.coerce.bigint().nonnegative(),\n minAmountOut: z.coerce.bigint().nonnegative(),\n fees: z.array(RecurringQuoteFeeSchema),\n recommendedSlippage: z.number().int().nonnegative(),\n expiredAt: z.number().int().nonnegative(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/orders` (list) endpoint.\n */\nexport const ListRecurringOrdersResponseSchema: z.ZodType<ListRecurringOrdersResponse> = z.object({\n address: EvmAddressSchema,\n count: z.number().int().nonnegative(),\n orders: z.array(RecurringOrderSchema),\n});\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{RECURRING_FREQUENCY_UNITS as e,RecurringOrderStatus as t}from"./types.js";import{EvmAddressSchema as n}from"../../service-schemas.js";import{z as r}from"zod";const i=/^0x[0-9a-fA-F]{64}$/,a=r.enum(e),o=r.object({unit:a,value:r.number().int().min(1)}),s=r.enum(Object.values(t)),c=r.object({executionIndex:r.number().int().nonnegative(),reasons:r.array(r.string()),tryCount:r.number().int().nonnegative(),failedAt:r.number().int().nonnegative()}),l=r.string().regex(i,`Invalid recurring order id (expected 0x-prefixed bytes32)`).transform(e=>e),u=r.object({orderId:l,owner:n,chainId:r.coerce.number().int().nonnegative(),tokenIn:n,tokenOut:n,amount:r.coerce.bigint().nonnegative(),numberOfOrders:r.number().int(),executedOrders:r.number().int().nonnegative(),remainingOrders:r.number().int().nonnegative().nullish().transform(e=>e??null),frequency:o,totalAmountIn:r.coerce.bigint().nonnegative(),tryCount:r.number().int().nonnegative(),failures:r.array(c),status:s,createdAt:r.number().int().nonnegative(),nextExecutionAt:r.number().int().nonnegative().nullish().transform(e=>e??null),cancelledAt:r.number().int().nonnegative().nullish().transform(e=>e??null)}),d=r.object({type:r.enum([`gas`,`recurring`,`protocol`,`bridge`,`slippage`,`swap`,`other`]).or(r.string()),name:r.string(),amount:r.coerce.bigint().nonnegative(),token:r.object({chainId:r.coerce.number().int().nonnegative(),address:n}),extra:r.union([r.boolean(),r.record(r.string(),r.unknown())]).optional()}),f=r.object({uuid:r.uuid(),chainId:r.coerce.number().int().nonnegative(),tokenIn:n,tokenOut:n,amount:r.coerce.bigint().nonnegative(),numberOfOrders:r.number().int(),frequency:o,intervalSeconds:r.number().int().nonnegative(),totalAmountIn:r.coerce.bigint().nonnegative(),amountOut:r.coerce.bigint().nonnegative(),minAmountOut:r.coerce.bigint().nonnegative(),fees:r.array(d),recommendedSlippage:r.number().int().nonnegative(),expiredAt:r.number().int().nonnegative()}),p=r.object({address:n,count:r.number().int().nonnegative(),orders:r.array(u)});export{p as ListRecurringOrdersResponseSchema,f as RecurringQuoteResponseSchema};
1
+ import{RECURRING_FREQUENCY_UNITS as e,RecurringOrderStatus as t}from"./types.js";import{EvmAddressSchema as n,HexSchema as r}from"../../service-schemas.js";import{z as i}from"zod";const a=/^0x[0-9a-fA-F]{64}$/,o=i.enum(e),s=i.object({unit:o,value:i.number().int().min(1)}),c=i.enum(Object.values(t)),l=i.object({executionIndex:i.number().int().nonnegative(),reasons:i.array(i.string()),tryCount:i.number().int().nonnegative(),failedAt:i.number().int().nonnegative()}),u=i.object({type:i.enum([`wrap`,`createOrder`]),to:n,data:r,value:i.coerce.bigint().nonnegative()}),d=i.array(u),f=i.string().regex(a,`Invalid recurring order id (expected 0x-prefixed bytes32)`).transform(e=>e),p=i.object({orderId:f,owner:n,chainId:i.coerce.number().int().nonnegative(),tokenIn:n,tokenOut:n,amount:i.coerce.bigint().nonnegative(),numberOfOrders:i.number().int(),executedOrders:i.number().int().nonnegative(),remainingOrders:i.number().int().nonnegative().nullish().transform(e=>e??null),frequency:s,totalAmountIn:i.coerce.bigint().nonnegative(),tryCount:i.number().int().nonnegative(),failures:i.array(l),status:c,createdAt:i.number().int().nonnegative(),nextExecutionAt:i.number().int().nonnegative().nullish().transform(e=>e??null),cancelledAt:i.number().int().nonnegative().nullish().transform(e=>e??null)}),m=i.object({type:i.enum([`gas`,`recurring`,`protocol`,`bridge`,`slippage`,`swap`,`other`]).or(i.string()),name:i.string(),amount:i.coerce.bigint().nonnegative(),token:i.object({chainId:i.coerce.number().int().nonnegative(),address:n}),extra:i.union([i.boolean(),i.record(i.string(),i.unknown())]).optional()}),h=i.object({uuid:i.uuid(),chainId:i.coerce.number().int().nonnegative(),tokenIn:n,tokenOut:n,amount:i.coerce.bigint().nonnegative(),numberOfOrders:i.number().int(),frequency:s,intervalSeconds:i.number().int().nonnegative(),totalAmountIn:i.coerce.bigint().nonnegative(),amountOut:i.coerce.bigint().nonnegative(),minAmountOut:i.coerce.bigint().nonnegative(),fees:i.array(m),recommendedSlippage:i.number().int().nonnegative(),expiredAt:i.number().int().nonnegative()}),g=i.object({address:n,count:i.number().int().nonnegative(),orders:i.array(p)});export{g as ListRecurringOrdersResponseSchema,h as RecurringQuoteResponseSchema,d as RecurringSwapResponseSchema};
2
2
  //# sourceMappingURL=_schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_schema.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_schema.ts"],"sourcesContent":["import { z } from 'zod';\nimport { EvmAddressSchema } from '../../service-schemas';\nimport {\n RECURRING_FREQUENCY_UNITS,\n RecurringOrderStatus,\n type ListRecurringOrdersResponse,\n type RecurringFrequency,\n type RecurringFrequencyUnit,\n type RecurringOrder,\n type RecurringOrderFailure,\n type RecurringQuoteResponse,\n} from './types';\n\nconst ORDER_ID_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\nexport const RecurringFrequencyUnitSchema: z.ZodType<RecurringFrequencyUnit> = z.enum(RECURRING_FREQUENCY_UNITS);\n\nexport const RecurringFrequencySchema: z.ZodType<RecurringFrequency> = z.object({\n unit: RecurringFrequencyUnitSchema,\n value: z.number().int().min(1),\n});\n\n/**\n * Closed enum — see {@link RecurringOrderStatus}. Unknown server-side values\n * (e.g. a hypothetical `'expired'`) will fail parsing loudly, which gates\n * UI behavior on an SDK update rather than silently surfacing an unhandled\n * status to the consumer.\n */\nexport const RecurringOrderStatusSchema: z.ZodType<RecurringOrderStatus> = z.enum(\n Object.values(RecurringOrderStatus) as [RecurringOrderStatus, ...RecurringOrderStatus[]],\n);\n\nexport const RecurringOrderFailureSchema: z.ZodType<RecurringOrderFailure> = z.object({\n // `nonnegative` (not `positive`) — Markr documents `executionIndex` as\n // 1-based today, but forward-compat with a future setup-time failure\n // emitting index `0` costs nothing and matches the same brittleness fix\n // applied to the status / fee-type enums.\n executionIndex: z.number().int().nonnegative(),\n reasons: z.array(z.string()),\n tryCount: z.number().int().nonnegative(),\n failedAt: z.number().int().nonnegative(),\n});\n\n/**\n * `0x`-prefixed bytes32 hex. Use `.transform()` to widen `string` into the\n * template-literal type that `RecurringOrder.orderId` declares — mirrors the\n * `EvmAddressSchema` pattern from `service-schemas.ts`.\n */\nconst OrderIdSchema: z.ZodType<`0x${string}`> = z\n .string()\n .regex(ORDER_ID_REGEX, 'Invalid recurring order id (expected 0x-prefixed bytes32)')\n .transform((value) => value as `0x${string}`);\n\n/**\n * Schema for a single `RecurringOrder` element as returned by Markr's\n * `/recurring/orders` (list) and `/recurring/orders/{orderId}/cancel`\n * endpoints.\n */\nexport const RecurringOrderSchema: z.ZodType<RecurringOrder> = z.object({\n orderId: OrderIdSchema,\n owner: EvmAddressSchema,\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n executedOrders: z.number().int().nonnegative(),\n // `null` (or omitted) on unlimited schedules per the Markr OpenAPI spec —\n // `numberOfOrders: -1` schedules have no finite remainder to report. Finite\n // schedules carry `numberOfOrders - executedOrders` as a non-negative int.\n // `.nullish()` accepts both `null` and `undefined`; we normalize to `null`\n // by coercing `undefined` via a default transform so consumers can use a\n // simple `if (order.remainingOrders === null)` check instead of also\n // guarding for `undefined`.\n remainingOrders: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n frequency: RecurringFrequencySchema,\n totalAmountIn: z.coerce.bigint().nonnegative(),\n tryCount: z.number().int().nonnegative(),\n failures: z.array(RecurringOrderFailureSchema),\n status: RecurringOrderStatusSchema,\n createdAt: z.number().int().nonnegative(),\n // OpenAPI marks `nextExecutionAt` as optional + nullable — accept all\n // three wire shapes (number / null / omitted) and normalize to\n // `number | null` so consumers can use a single `=== null` check.\n // Same pattern as `remainingOrders` above.\n nextExecutionAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n // OpenAPI marks `cancelledAt` as optional + nullable; populated only when\n // `status === 'cancelled'`. Normalize to `number | null` (always present\n // in the parsed shape) for the same consumer-ergonomics reason as\n // `nextExecutionAt` / `remainingOrders`.\n cancelledAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n});\n\nconst RecurringQuoteFeeSchema = z.object({\n // Tolerant of unknown fee categories (forward-compat). Unlike\n // `RecurringOrderStatusSchema` (closed enum — see comment there), a new\n // fee category from Markr is safe to render as \"Other fee\" instead of\n // bricking parsing on already-shipped clients.\n type: z.enum(['gas', 'recurring', 'protocol', 'bridge', 'slippage', 'swap', 'other']).or(z.string()),\n name: z.string(),\n amount: z.coerce.bigint().nonnegative(),\n token: z.object({\n chainId: z.coerce.number().int().nonnegative(),\n address: EvmAddressSchema,\n }),\n // Docs: `extra: boolean or object` — accept both. See the equivalent\n // widening on the one-shot quote schema in `markr/_schema.ts`.\n extra: z.union([z.boolean(), z.record(z.string(), z.unknown())]).optional(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/quote` endpoint.\n */\nexport const RecurringQuoteResponseSchema: z.ZodType<RecurringQuoteResponse> = z.object({\n uuid: z.uuid(),\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n frequency: RecurringFrequencySchema,\n intervalSeconds: z.number().int().nonnegative(),\n totalAmountIn: z.coerce.bigint().nonnegative(),\n amountOut: z.coerce.bigint().nonnegative(),\n minAmountOut: z.coerce.bigint().nonnegative(),\n fees: z.array(RecurringQuoteFeeSchema),\n recommendedSlippage: z.number().int().nonnegative(),\n expiredAt: z.number().int().nonnegative(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/orders` (list) endpoint.\n */\nexport const ListRecurringOrdersResponseSchema: z.ZodType<ListRecurringOrdersResponse> = z.object({\n address: EvmAddressSchema,\n count: z.number().int().nonnegative(),\n orders: z.array(RecurringOrderSchema),\n});\n"],"mappings":"qKAaA,MAAM,EAAiB,sBAEV,EAAkE,EAAE,KAAK,EAA0B,CAEnG,EAA0D,EAAE,OAAO,CAC9E,KAAM,EACN,MAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAC/B,CAAC,CAQW,EAA8D,EAAE,KAC3E,OAAO,OAAO,EAAqB,CACpC,CAEY,EAAgE,EAAE,OAAO,CAKpF,eAAgB,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAC9C,QAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAC5B,SAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CACxC,SAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CACzC,CAAC,CAOI,EAA0C,EAC7C,QAAQ,CACR,MAAM,EAAgB,4DAA4D,CAClF,UAAW,GAAU,EAAuB,CAOlC,EAAkD,EAAE,OAAO,CACtE,QAAS,EACT,MAAO,EACP,QAAS,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,aAAa,CAC9C,QAAS,EACT,SAAU,EACV,OAAQ,EAAE,OAAO,QAAQ,CAAC,aAAa,CACvC,eAAgB,EAAE,QAAQ,CAAC,KAAK,CAChC,eAAgB,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAQ9C,gBAAiB,EACd,QAAQ,CACR,KAAK,CACL,aAAa,CACb,SAAS,CACT,UAAW,GAAU,GAAS,KAAK,CACtC,UAAW,EACX,cAAe,EAAE,OAAO,QAAQ,CAAC,aAAa,CAC9C,SAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CACxC,SAAU,EAAE,MAAM,EAA4B,CAC9C,OAAQ,EACR,UAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAKzC,gBAAiB,EACd,QAAQ,CACR,KAAK,CACL,aAAa,CACb,SAAS,CACT,UAAW,GAAU,GAAS,KAAK,CAKtC,YAAa,EACV,QAAQ,CACR,KAAK,CACL,aAAa,CACb,SAAS,CACT,UAAW,GAAU,GAAS,KAAK,CACvC,CAAC,CAEI,EAA0B,EAAE,OAAO,CAKvC,KAAM,EAAE,KAAK,CAAC,MAAO,YAAa,WAAY,SAAU,WAAY,OAAQ,QAAQ,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,CACpG,KAAM,EAAE,QAAQ,CAChB,OAAQ,EAAE,OAAO,QAAQ,CAAC,aAAa,CACvC,MAAO,EAAE,OAAO,CACd,QAAS,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,aAAa,CAC9C,QAAS,EACV,CAAC,CAGF,MAAO,EAAE,MAAM,CAAC,EAAE,SAAS,CAAE,EAAE,OAAO,EAAE,QAAQ,CAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAC5E,CAAC,CAKW,EAAkE,EAAE,OAAO,CACtF,KAAM,EAAE,MAAM,CACd,QAAS,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,aAAa,CAC9C,QAAS,EACT,SAAU,EACV,OAAQ,EAAE,OAAO,QAAQ,CAAC,aAAa,CACvC,eAAgB,EAAE,QAAQ,CAAC,KAAK,CAChC,UAAW,EACX,gBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAC/C,cAAe,EAAE,OAAO,QAAQ,CAAC,aAAa,CAC9C,UAAW,EAAE,OAAO,QAAQ,CAAC,aAAa,CAC1C,aAAc,EAAE,OAAO,QAAQ,CAAC,aAAa,CAC7C,KAAM,EAAE,MAAM,EAAwB,CACtC,oBAAqB,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CACnD,UAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAC1C,CAAC,CAKW,EAA4E,EAAE,OAAO,CAChG,QAAS,EACT,MAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CACrC,OAAQ,EAAE,MAAM,EAAqB,CACtC,CAAC"}
1
+ {"version":3,"file":"_schema.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_schema.ts"],"sourcesContent":["import { z } from 'zod';\nimport { EvmAddressSchema, HexSchema } from '../../service-schemas';\nimport {\n RECURRING_FREQUENCY_UNITS,\n RecurringOrderStatus,\n type ListRecurringOrdersResponse,\n type RecurringFrequency,\n type RecurringFrequencyUnit,\n type RecurringOrder,\n type RecurringOrderFailure,\n type RecurringQuoteResponse,\n type RecurringSwapResponse,\n type RecurringSwapTransaction,\n} from './types';\n\nconst ORDER_ID_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\nexport const RecurringFrequencyUnitSchema: z.ZodType<RecurringFrequencyUnit> = z.enum(RECURRING_FREQUENCY_UNITS);\n\nexport const RecurringFrequencySchema: z.ZodType<RecurringFrequency> = z.object({\n unit: RecurringFrequencyUnitSchema,\n value: z.number().int().min(1),\n});\n\n/**\n * Closed enum — see {@link RecurringOrderStatus}. Unknown server-side values\n * (e.g. a hypothetical `'expired'`) will fail parsing loudly, which gates\n * UI behavior on an SDK update rather than silently surfacing an unhandled\n * status to the consumer.\n */\nexport const RecurringOrderStatusSchema: z.ZodType<RecurringOrderStatus> = z.enum(\n Object.values(RecurringOrderStatus) as [RecurringOrderStatus, ...RecurringOrderStatus[]],\n);\n\nexport const RecurringOrderFailureSchema: z.ZodType<RecurringOrderFailure> = z.object({\n // `nonnegative` (not `positive`) — Markr documents `executionIndex` as\n // 1-based today, but forward-compat with a future setup-time failure\n // emitting index `0` costs nothing and matches the same brittleness fix\n // applied to the status / fee-type enums.\n executionIndex: z.number().int().nonnegative(),\n reasons: z.array(z.string()),\n tryCount: z.number().int().nonnegative(),\n failedAt: z.number().int().nonnegative(),\n});\n\n/**\n * Schema for a single step in {@link RecurringSwapResponse}. Markr's\n * `/recurring/swap` doc documents two `type` values; we keep this as a\n * closed enum so an unrecognized step (e.g. a hypothetical future\n * `'approve'`) fails parsing loudly — the SDK builds the approval itself\n * and a server-side change to that contract should gate on an SDK update.\n */\nexport const RecurringSwapTransactionSchema: z.ZodType<RecurringSwapTransaction> = z.object({\n type: z.enum(['wrap', 'createOrder']),\n to: EvmAddressSchema,\n data: HexSchema,\n value: z.coerce.bigint().nonnegative(),\n});\n\n/**\n * Response schema for Markr's `/recurring/swap`. Always an array, ordered;\n * the consumer signs each entry in array order. See\n * {@link RecurringSwapResponse}.\n */\nexport const RecurringSwapResponseSchema: z.ZodType<RecurringSwapResponse> = z.array(RecurringSwapTransactionSchema);\n\n/**\n * `0x`-prefixed bytes32 hex. Use `.transform()` to widen `string` into the\n * template-literal type that `RecurringOrder.orderId` declares — mirrors the\n * `EvmAddressSchema` pattern from `service-schemas.ts`.\n */\nconst OrderIdSchema: z.ZodType<`0x${string}`> = z\n .string()\n .regex(ORDER_ID_REGEX, 'Invalid recurring order id (expected 0x-prefixed bytes32)')\n .transform((value) => value as `0x${string}`);\n\n/**\n * Schema for a single `RecurringOrder` element as returned by Markr's\n * `/recurring/orders` (list) and `/recurring/orders/{orderId}/cancel`\n * endpoints.\n */\nexport const RecurringOrderSchema: z.ZodType<RecurringOrder> = z.object({\n orderId: OrderIdSchema,\n owner: EvmAddressSchema,\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n executedOrders: z.number().int().nonnegative(),\n // `null` (or omitted) on unlimited schedules per the Markr OpenAPI spec —\n // `numberOfOrders: -1` schedules have no finite remainder to report. Finite\n // schedules carry `numberOfOrders - executedOrders` as a non-negative int.\n // `.nullish()` accepts both `null` and `undefined`; we normalize to `null`\n // by coercing `undefined` via a default transform so consumers can use a\n // simple `if (order.remainingOrders === null)` check instead of also\n // guarding for `undefined`.\n remainingOrders: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n frequency: RecurringFrequencySchema,\n totalAmountIn: z.coerce.bigint().nonnegative(),\n tryCount: z.number().int().nonnegative(),\n failures: z.array(RecurringOrderFailureSchema),\n status: RecurringOrderStatusSchema,\n createdAt: z.number().int().nonnegative(),\n // OpenAPI marks `nextExecutionAt` as optional + nullable — accept all\n // three wire shapes (number / null / omitted) and normalize to\n // `number | null` so consumers can use a single `=== null` check.\n // Same pattern as `remainingOrders` above.\n nextExecutionAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n // OpenAPI marks `cancelledAt` as optional + nullable; populated only when\n // `status === 'cancelled'`. Normalize to `number | null` (always present\n // in the parsed shape) for the same consumer-ergonomics reason as\n // `nextExecutionAt` / `remainingOrders`.\n cancelledAt: z\n .number()\n .int()\n .nonnegative()\n .nullish()\n .transform((value) => value ?? null),\n});\n\nconst RecurringQuoteFeeSchema = z.object({\n // Tolerant of unknown fee categories (forward-compat). Unlike\n // `RecurringOrderStatusSchema` (closed enum — see comment there), a new\n // fee category from Markr is safe to render as \"Other fee\" instead of\n // bricking parsing on already-shipped clients.\n type: z.enum(['gas', 'recurring', 'protocol', 'bridge', 'slippage', 'swap', 'other']).or(z.string()),\n name: z.string(),\n amount: z.coerce.bigint().nonnegative(),\n token: z.object({\n chainId: z.coerce.number().int().nonnegative(),\n address: EvmAddressSchema,\n }),\n // Docs: `extra: boolean or object` — accept both. See the equivalent\n // widening on the one-shot quote schema in `markr/_schema.ts`.\n extra: z.union([z.boolean(), z.record(z.string(), z.unknown())]).optional(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/quote` endpoint.\n */\nexport const RecurringQuoteResponseSchema: z.ZodType<RecurringQuoteResponse> = z.object({\n uuid: z.uuid(),\n chainId: z.coerce.number().int().nonnegative(),\n tokenIn: EvmAddressSchema,\n tokenOut: EvmAddressSchema,\n amount: z.coerce.bigint().nonnegative(),\n numberOfOrders: z.number().int(),\n frequency: RecurringFrequencySchema,\n intervalSeconds: z.number().int().nonnegative(),\n totalAmountIn: z.coerce.bigint().nonnegative(),\n amountOut: z.coerce.bigint().nonnegative(),\n minAmountOut: z.coerce.bigint().nonnegative(),\n fees: z.array(RecurringQuoteFeeSchema),\n recommendedSlippage: z.number().int().nonnegative(),\n expiredAt: z.number().int().nonnegative(),\n});\n\n/**\n * Schema for the response from Markr's `/recurring/orders` (list) endpoint.\n */\nexport const ListRecurringOrdersResponseSchema: z.ZodType<ListRecurringOrdersResponse> = z.object({\n address: EvmAddressSchema,\n count: z.number().int().nonnegative(),\n orders: z.array(RecurringOrderSchema),\n});\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=[`minute`,`hour`,`day`,`week`,`month`];let t=function(e){return e.Active=`active`,e.Completed=`completed`,e.Cancelled=`cancelled`,e.Paused=`paused`,e}({}),n=function(e){return e.CrossChain=`cross-chain`,e.UnsupportedSourceChain=`unsupported-source-chain`,e.UnsupportedToken=`unsupported-token`,e.NoEvmAddress=`no-evm-address`,e.AmountBelowMinimum=`amount-below-minimum`,e}({});exports.RECURRING_FREQUENCY_UNITS=e,exports.RECURRING_UNLIMITED_ORDERS_SENTINEL=-1,exports.RecurringEligibilityReason=n,exports.RecurringOrderStatus=t;
1
+ const e=[`minute`,`hour`,`day`,`week`,`month`];let t=function(e){return e.Active=`active`,e.Completed=`completed`,e.Cancelled=`cancelled`,e.Paused=`paused`,e}({}),n=function(e){return e.CrossChain=`cross-chain`,e.UnsupportedSourceChain=`unsupported-source-chain`,e.UnsupportedToken=`unsupported-token`,e.NoEvmAddress=`no-evm-address`,e.NativeToWrappedNative=`native-to-wrapped-native`,e}({});exports.RECURRING_FREQUENCY_UNITS=e,exports.RECURRING_UNLIMITED_ORDERS_SENTINEL=-1,exports.RecurringEligibilityReason=n,exports.RecurringOrderStatus=t;
2
2
  //# sourceMappingURL=types.cjs.map