@@ -10,6 +10,7 @@ const deployment = defaults.machineToken[chainId]
1010const targetToken = '0x20c0000000000000000000000000000000000001'
1111const recipient = '0x2222222222222222222222222222222222222222'
1212const payer = '0x1111111111111111111111111111111111111111'
13+ const sessionPayee = '0x44d7c1edfdfdfdfdfdfdfdfd0000000000000001'
1314const memo = `0x${ 'ab' . repeat ( 32 ) } ` as const
1415const client = createClient ( {
1516 transport : custom ( { request : async ( ) => undefined as never } ) ,
@@ -176,4 +177,145 @@ describe('Tempo machine token', () => {
176177 } ) ,
177178 ) . toBeUndefined ( )
178179 } )
180+
181+ test ( 'resolves active session routes without exposing them to merchant configuration' , async ( ) => {
182+ vi . resetModules ( )
183+ vi . doMock ( 'viem/actions' , ( ) => ( {
184+ call : vi . fn ( ) ,
185+ readContract : vi . fn ( async ( _client , parameters : { functionName : string } ) => {
186+ if ( parameters . functionName === 'sessionRouteFor' ) return sessionPayee
187+ if ( parameters . functionName === 'sessionRoutes' ) return [ recipient , targetToken ]
188+ throw new Error ( `unexpected function ${ parameters . functionName } ` )
189+ } ) ,
190+ } ) )
191+
192+ try {
193+ const MachineToken = await import ( './machine-token.js' )
194+ await expect (
195+ MachineToken . findSessionRoute ( client , {
196+ chainId,
197+ merchant : recipient ,
198+ targetToken,
199+ } ) ,
200+ ) . resolves . toEqual ( {
201+ merchant : recipient ,
202+ operator : deployment . swap ,
203+ payee : sessionPayee ,
204+ targetToken,
205+ token : deployment . token ,
206+ } )
207+ await expect (
208+ MachineToken . getSessionRoute ( client , { chainId, payee : sessionPayee } ) ,
209+ ) . resolves . toEqual ( {
210+ merchant : recipient ,
211+ operator : deployment . swap ,
212+ payee : sessionPayee ,
213+ targetToken,
214+ token : deployment . token ,
215+ } )
216+ await expect (
217+ MachineToken . findVerifiedSessionRoute ( client , {
218+ chainId,
219+ merchant : recipient ,
220+ targetToken,
221+ } ) ,
222+ ) . resolves . toEqual ( expect . objectContaining ( { merchant : recipient , payee : sessionPayee } ) )
223+ await expect (
224+ MachineToken . resolveSessionRoute ( client , { chainId, payee : sessionPayee } ) ,
225+ ) . resolves . toEqual ( {
226+ merchant : recipient ,
227+ operator : deployment . swap ,
228+ payee : sessionPayee ,
229+ targetToken,
230+ token : deployment . token ,
231+ } )
232+ await expect (
233+ MachineToken . matchSessionRoute ( client , {
234+ chainId,
235+ descriptor : {
236+ operator : deployment . swap ,
237+ payee : sessionPayee ,
238+ token : deployment . token ,
239+ } ,
240+ merchant : recipient ,
241+ targetToken,
242+ } ) ,
243+ ) . resolves . toEqual ( expect . objectContaining ( { merchant : recipient , targetToken } ) )
244+ await expect (
245+ MachineToken . matchSessionRoute ( client , {
246+ chainId,
247+ descriptor : {
248+ operator : deployment . swap ,
249+ payee : sessionPayee ,
250+ token : deployment . token ,
251+ } ,
252+ merchant : payer ,
253+ targetToken,
254+ } ) ,
255+ ) . resolves . toBeUndefined ( )
256+ expect ( MachineToken . isSessionSupported ( chainId ) ) . toBe ( true )
257+ expect ( MachineToken . isSessionSupported ( defaults . chainId . mainnet ) ) . toBe ( false )
258+ expect ( MachineToken . getSessionFeeToken ( chainId ) ) . toBe ( defaults . tokens . pathUsd )
259+ expect ( MachineToken . getSessionFeeToken ( defaults . chainId . mainnet ) ) . toBeUndefined ( )
260+ } finally {
261+ vi . doUnmock ( 'viem/actions' )
262+ vi . resetModules ( )
263+ }
264+ } )
265+
266+ test ( 'separates the challenge capability flag from the trusted descriptor pair' , async ( ) => {
267+ const MachineToken = await import ( './machine-token.js' )
268+ expect (
269+ MachineToken . isSessionEnabledChallenge ( {
270+ request : { methodDetails : { chainId, machineTokenEnabled : true } } ,
271+ } ) ,
272+ ) . toBe ( true )
273+ expect (
274+ MachineToken . isSessionEnabledChallenge ( {
275+ request : { methodDetails : { chainId, machineTokenEnabled : false } } ,
276+ } ) ,
277+ ) . toBe ( false )
278+ expect (
279+ MachineToken . matchSessionDescriptor ( {
280+ chainId,
281+ descriptor : { operator : deployment . swap , token : deployment . token } ,
282+ } ) ,
283+ ) . toEqual ( deployment )
284+ expect (
285+ MachineToken . matchSessionDescriptor ( {
286+ chainId,
287+ descriptor : { operator : recipient , token : deployment . token } ,
288+ } ) ,
289+ ) . toBeUndefined ( )
290+ } )
291+
292+ test ( 'rejects virtual payees that are no longer the active merchant route' , async ( ) => {
293+ vi . resetModules ( )
294+ vi . doMock ( 'viem/actions' , ( ) => ( {
295+ call : vi . fn ( ) ,
296+ readContract : vi . fn ( async ( _client , parameters : { functionName : string } ) => {
297+ if ( parameters . functionName === 'sessionRoutes' ) return [ recipient , targetToken ]
298+ if ( parameters . functionName === 'sessionRouteFor' )
299+ return '0x0000000000000000000000000000000000000000'
300+ throw new Error ( `unexpected function ${ parameters . functionName } ` )
301+ } ) ,
302+ } ) )
303+
304+ try {
305+ const MachineToken = await import ( './machine-token.js' )
306+ await expect (
307+ MachineToken . resolveSessionRoute ( client , { chainId, payee : sessionPayee } ) ,
308+ ) . resolves . toBeUndefined ( )
309+ await expect (
310+ MachineToken . resolveSessionRoute ( client , {
311+ active : false ,
312+ chainId,
313+ payee : sessionPayee ,
314+ } ) ,
315+ ) . resolves . toEqual ( expect . objectContaining ( { merchant : recipient , targetToken } ) )
316+ } finally {
317+ vi . doUnmock ( 'viem/actions' )
318+ vi . resetModules ( )
319+ }
320+ } )
179321} )
0 commit comments