@@ -2,6 +2,7 @@ import { Asset, Cardano } from '@cardano-sdk/core';
2
2
import { Buffer } from 'buffer' ;
3
3
import { Mappers , ProjectionEvent } from '../../../src' ;
4
4
import {
5
+ NFTSubHandleOutput ,
5
6
assetIdFromHandle ,
6
7
bobAddress ,
7
8
bobHandleOne ,
@@ -11,14 +12,32 @@ import {
11
12
maryAddress ,
12
13
maryHandleOne ,
13
14
referenceNftOutput ,
14
- userNftOutput
15
+ subhandleAssetName ,
16
+ userNftOutput ,
17
+ virtualHandleAssetName ,
18
+ virtualSubHandleOutput
15
19
} from './handleUtil' ;
16
20
import { firstValueFrom , of } from 'rxjs' ;
17
21
import { logger , mockProviders } from '@cardano-sdk/util-dev' ;
18
- import { withCIP67 , withHandles , withUtxo } from '../../../src/operators/Mappers' ;
22
+ import { withCIP67 , withHandles , withMint , withUtxo } from '../../../src/operators/Mappers' ;
19
23
20
24
type In = Mappers . WithMint & Mappers . WithCIP67 & Mappers . WithNftMetadata ;
21
25
26
+ const project = ( tx : Cardano . OnChainTx ) =>
27
+ firstValueFrom (
28
+ of ( {
29
+ block : {
30
+ body : [ tx ] ,
31
+ header : mockProviders . ledgerTip
32
+ }
33
+ } as ProjectionEvent ) . pipe (
34
+ withUtxo ( ) ,
35
+ withMint ( ) ,
36
+ withCIP67 ( ) ,
37
+ withHandles ( { policyIds : [ handlePolicyId ] } , logger )
38
+ )
39
+ ) ;
40
+
22
41
describe ( 'withHandles' , ( ) => {
23
42
it ( 'sets "datum" property on the handle if utxo has datum' , async ( ) => {
24
43
const datum = Buffer . from ( '123abc' , 'hex' ) ;
@@ -246,17 +265,6 @@ describe('withHandles', () => {
246
265
} ) ;
247
266
248
267
describe ( 'cip68' , ( ) => {
249
- // eslint-disable-next-line unicorn/consistent-function-scoping
250
- const project = ( tx : Cardano . OnChainTx ) =>
251
- firstValueFrom (
252
- of ( {
253
- block : {
254
- body : [ tx ] ,
255
- header : mockProviders . ledgerTip
256
- }
257
- } as ProjectionEvent ) . pipe ( withUtxo ( ) , withCIP67 ( ) , withHandles ( { policyIds : [ handlePolicyId ] } , logger ) )
258
- ) ;
259
-
260
268
it ( 'does not change ownership when only reference token is present' , async ( ) => {
261
269
const { handles } = await project ( {
262
270
body : { outputs : [ referenceNftOutput ] } ,
@@ -288,4 +296,61 @@ describe('withHandles', () => {
288
296
expect ( handles [ 0 ] . latestOwnerAddress ) . toBe ( maryAddress ) ;
289
297
} ) ;
290
298
} ) ;
299
+
300
+ describe ( 'subhandles' , ( ) => {
301
+ it ( 'adds parentHandle data for virtual subhandles' , async ( ) => {
302
+ const { handles } = await project ( {
303
+ body : { outputs : [ virtualSubHandleOutput ] } ,
304
+ inputSource : Cardano . InputSource . inputs
305
+ } as Cardano . OnChainTx ) ;
306
+
307
+ expect ( handles ) . toHaveLength ( 1 ) ;
308
+
309
+ expect ( handles [ 0 ] . latestOwnerAddress ) . toBe (
310
+ 'addr_test1qpadxfxylvy8p8wejlmt9wnesr2squgr524r77n7hz6yh3h34r3hjynmsy2cxpc04a6dkqxcsr29qfl7v9cmrd5mm89qqh563f'
311
+ ) ;
312
+ expect ( handles [ 0 ] . parentHandle ) . toBe ( 'handl' ) ;
313
+ expect ( handles [ 0 ] . handle ) . toBe ( 'virtual@handl' ) ;
314
+ } ) ;
315
+
316
+ it ( 'adds parentHandle data for NFT subhandles' , async ( ) => {
317
+ const { handles } = await project ( {
318
+ body : { outputs : [ NFTSubHandleOutput ] } ,
319
+ inputSource : Cardano . InputSource . inputs
320
+ } as Cardano . OnChainTx ) ;
321
+
322
+ expect ( handles ) . toHaveLength ( 1 ) ;
323
+
324
+ expect ( handles [ 0 ] . parentHandle ) . toBe ( 'handl' ) ;
325
+ expect ( handles [ 0 ] . handle ) . toBe ( 'sub@handl' ) ;
326
+ } ) ;
327
+
328
+ it ( 'includes a handle with "null" address, when transaction burns a subhandle' , async ( ) => {
329
+ const { handles } = await project ( {
330
+ body : {
331
+ mint : new Map ( [ [ Cardano . AssetId . fromParts ( handlePolicyId , subhandleAssetName ) , - 1n ] ] ) ,
332
+ outputs : [ ] as Cardano . TxOut [ ]
333
+ } ,
334
+ inputSource : Cardano . InputSource . inputs
335
+ } as Cardano . OnChainTx ) ;
336
+
337
+ expect ( handles . length ) . toBe ( 1 ) ;
338
+ expect ( handles [ 0 ] . latestOwnerAddress ) . toBeNull ( ) ;
339
+ expect ( handles [ 0 ] . handle ) . toBe ( 'sub@handl' ) ;
340
+ } ) ;
341
+
342
+ it ( 'includes a handle with "null" address, when transaction burns a virtualSubhandle' , async ( ) => {
343
+ const { handles } = await project ( {
344
+ body : {
345
+ mint : new Map ( [ [ Cardano . AssetId . fromParts ( handlePolicyId , virtualHandleAssetName ) , - 1n ] ] ) ,
346
+ outputs : [ ] as Cardano . TxOut [ ]
347
+ } ,
348
+ inputSource : Cardano . InputSource . inputs
349
+ } as Cardano . OnChainTx ) ;
350
+
351
+ expect ( handles . length ) . toBe ( 1 ) ;
352
+ expect ( handles [ 0 ] . latestOwnerAddress ) . toBeNull ( ) ;
353
+ expect ( handles [ 0 ] . handle ) . toBe ( 'virtual@handl' ) ;
354
+ } ) ;
355
+ } ) ;
291
356
} ) ;
0 commit comments