@@ -207,7 +207,9 @@ describe("Dispute Functions", () => {
207207 transport : http ( RPC ) ,
208208 account : privateKeyToAccount ( process . env . JUDGE_PRIVATE_KEY as Address ) ,
209209 } ) ;
210+ } ) ;
210211
212+ beforeEach ( async function ( this : Mocha . Context ) {
211213 // Setup NFT collection
212214 const txData = await clientA . nftClient . createNFTCollection ( {
213215 name : "test-collection" ,
@@ -335,8 +337,248 @@ describe("Dispute Functions", () => {
335337 expect ( results [ 0 ] . txHash ) . to . be . a ( "string" ) . and . not . empty ;
336338 } ) ;
337339
338- // Test that dispute initiator can resolve the dispute after judgement
340+ it ( "should tag a single IP as infringing without using multicall" , async ( ) => {
341+ /**
342+ * Test Flow:
343+ * 1. Set judgment on an existing dispute to mark it as valid
344+ * 2. Verify the dispute state changed correctly after judgment
345+ * 3. Try to tag a derivative IP using the judged dispute
346+ */
347+
348+ // Step 1: Set dispute judgment using the judge wallet
349+ // When judgment is true, the dispute's currentTag will be set to the targetTag
350+ // When false, currentTag would be set to bytes32(0)
351+ const { request } = await publicClient . simulateContract ( {
352+ address : DISPUTE_MODULE_ADDRESS ,
353+ abi : [ SET_DISPUTE_JUDGEMENT_ABI ] ,
354+ functionName : "setDisputeJudgement" ,
355+ args : [ disputeId , true , "0x" ] ,
356+ account : judgeWalletClient . account ! ,
357+ } ) ;
358+ const judgmentTxHash = await judgeWalletClient . writeContract ( request ) ;
359+ await publicClient . waitForTransactionReceipt ( { hash : judgmentTxHash } ) ;
360+
361+ // Step 2: Verify dispute state
362+ // The disputes() function returns multiple values about the dispute:
363+ // - targetTag: the tag we wanted to apply when raising the dispute
364+ // - currentTag: the current state of the dispute after judgment
365+ // After a successful judgment, currentTag should equal targetTag
366+ const [
367+ _targetIpId , // IP being disputed
368+ _disputeInitiator , // Address that raised the dispute
369+ _disputeTimestamp , // When dispute was raised
370+ _arbitrationPolicy , // Policy used for arbitration
371+ _disputeEvidenceHash , // Evidence hash for dispute
372+ targetTag , // Tag we want to apply (e.g. "IMPROPER_REGISTRATION")
373+ currentTag , // Current state of dispute
374+ _infringerDisputeId , // Related dispute ID if this is a propagated tag
375+ ] = await publicClient . readContract ( {
376+ address : disputeModuleAddress [ aeneid ] ,
377+ abi : disputeModuleAbi ,
378+ functionName : "disputes" ,
379+ args : [ disputeId ] ,
380+ } ) ;
381+ expect ( currentTag ) . to . equal ( targetTag ) ; // Verify judgment was recorded correctly
382+
383+ // Step 3: Attempt to tag a derivative IP
384+ // This will fail if:
385+ // - The dispute is not in a valid state (still IN_DISPUTE or cleared)
386+ // - The IP we're trying to tag is not actually a derivative of the disputed IP
387+ // - The dispute has already been used to tag this IP
388+ const response = await clientA . dispute . tagIfRelatedIpInfringed ( {
389+ infringementTags : [
390+ {
391+ ipId : childIpId , // The derivative IP to tag
392+ disputeId : disputeId , // Using the judged dispute as basis for tagging
393+ } ,
394+ ] ,
395+ options : {
396+ useMulticallWhenPossible : false , // Force single transaction instead of batch
397+ } ,
398+ txOptions : { waitForTransaction : true } ,
399+ } ) ;
400+
401+ // Verify we got the expected response
402+ expect ( response ) . to . have . lengthOf ( 1 ) ;
403+ expect ( response [ 0 ] . txHash ) . to . be . a ( "string" ) . and . not . empty ;
404+ } ) ;
405+
406+ it ( "should tag multiple IPs as infringing using multicall" , async ( ) => {
407+ const disputeResponse = await clientA . dispute . raiseDispute ( {
408+ targetIpId : parentIpId ,
409+ cid : await generateCID ( ) ,
410+ targetTag : "IMPROPER_REGISTRATION" ,
411+ liveness : 2592000 ,
412+ bond : 0 ,
413+ txOptions : { waitForTransaction : true } ,
414+ } ) ;
415+ const testDisputeId = disputeResponse . disputeId ! ;
416+
417+ const derivativeResponse2 = await clientA . ipAsset . mintAndRegisterIpAndMakeDerivative ( {
418+ spgNftContract : nftContract ,
419+ derivData : {
420+ parentIpIds : [ parentIpId ! ] ,
421+ licenseTermsIds : [ licenseTermsId ! ] ,
422+ maxMintingFee : 1n ,
423+ maxRts : 5 * 10 ** 6 ,
424+ maxRevenueShare : 100 ,
425+ } ,
426+ allowDuplicates : true ,
427+ txOptions : { waitForTransaction : true } ,
428+ } ) ;
429+ const childIpId2 = derivativeResponse2 . ipId ! ;
430+
431+ const { request } = await publicClient . simulateContract ( {
432+ address : DISPUTE_MODULE_ADDRESS ,
433+ abi : [ SET_DISPUTE_JUDGEMENT_ABI ] ,
434+ functionName : "setDisputeJudgement" ,
435+ args : [ testDisputeId , true , "0x" ] ,
436+ account : judgeWalletClient . account ! ,
437+ } ) ;
438+ const judgmentTxHash = await judgeWalletClient . writeContract ( request ) ;
439+ await publicClient . waitForTransactionReceipt ( { hash : judgmentTxHash } ) ;
440+
441+ const disputeState = await publicClient . readContract ( {
442+ address : disputeModuleAddress [ aeneid ] ,
443+ abi : disputeModuleAbi ,
444+ functionName : "disputes" ,
445+ args : [ testDisputeId ] ,
446+ } ) ;
447+ expect ( disputeState [ 6 ] ) . to . equal ( disputeState [ 5 ] ) ;
448+
449+ const response = await clientA . dispute . tagIfRelatedIpInfringed ( {
450+ infringementTags : [
451+ {
452+ ipId : childIpId ,
453+ disputeId : testDisputeId ,
454+ } ,
455+ {
456+ ipId : childIpId2 ,
457+ disputeId : testDisputeId ,
458+ } ,
459+ ] ,
460+ options : {
461+ useMulticallWhenPossible : true ,
462+ } ,
463+ txOptions : { waitForTransaction : true } ,
464+ } ) ;
465+
466+ expect ( response ) . to . have . lengthOf ( 1 ) ;
467+ expect ( response [ 0 ] . txHash ) . to . be . a ( "string" ) . and . not . empty ;
468+ } ) ;
469+
470+ it ( "should tag multiple IPs without multicall when specified" , async ( ) => {
471+ // Create two new derivative IPs sequentially
472+ const derivativeResponse3 = await clientA . ipAsset . mintAndRegisterIpAndMakeDerivative ( {
473+ spgNftContract : nftContract ,
474+ derivData : {
475+ parentIpIds : [ parentIpId ! ] ,
476+ licenseTermsIds : [ licenseTermsId ! ] ,
477+ maxMintingFee : 1n ,
478+ maxRts : 5 * 10 ** 6 ,
479+ maxRevenueShare : 100 ,
480+ } ,
481+ allowDuplicates : true ,
482+ txOptions : { waitForTransaction : true } ,
483+ } ) ;
484+
485+ const derivativeResponse4 = await clientA . ipAsset . mintAndRegisterIpAndMakeDerivative ( {
486+ spgNftContract : nftContract ,
487+ derivData : {
488+ parentIpIds : [ parentIpId ! ] ,
489+ licenseTermsIds : [ licenseTermsId ! ] ,
490+ maxMintingFee : 1n ,
491+ maxRts : 5 * 10 ** 6 ,
492+ maxRevenueShare : 100 ,
493+ } ,
494+ allowDuplicates : true ,
495+ txOptions : { waitForTransaction : true } ,
496+ } ) ;
497+
498+ const { request } = await publicClient . simulateContract ( {
499+ address : DISPUTE_MODULE_ADDRESS ,
500+ abi : [ SET_DISPUTE_JUDGEMENT_ABI ] ,
501+ functionName : "setDisputeJudgement" ,
502+ args : [ disputeId , true , "0x" ] ,
503+ account : judgeWalletClient . account ! ,
504+ } ) ;
505+ const judgmentTxHash = await judgeWalletClient . writeContract ( request ) ;
506+ await publicClient . waitForTransactionReceipt ( { hash : judgmentTxHash } ) ;
507+
508+ const disputeState = await publicClient . readContract ( {
509+ address : disputeModuleAddress [ aeneid ] ,
510+ abi : disputeModuleAbi ,
511+ functionName : "disputes" ,
512+ args : [ disputeId ] ,
513+ } ) ;
514+ expect ( disputeState [ 6 ] ) . to . equal ( disputeState [ 5 ] ) ;
515+
516+ const response1 = await clientA . dispute . tagIfRelatedIpInfringed ( {
517+ infringementTags : [
518+ {
519+ ipId : derivativeResponse3 . ipId ! ,
520+ disputeId : disputeId ,
521+ } ,
522+ ] ,
523+ options : {
524+ useMulticallWhenPossible : false ,
525+ } ,
526+ txOptions : { waitForTransaction : true } ,
527+ } ) ;
528+
529+ const response2 = await clientA . dispute . tagIfRelatedIpInfringed ( {
530+ infringementTags : [
531+ {
532+ ipId : derivativeResponse4 . ipId ! ,
533+ disputeId : disputeId ,
534+ } ,
535+ ] ,
536+ options : {
537+ useMulticallWhenPossible : false ,
538+ } ,
539+ txOptions : { waitForTransaction : true } ,
540+ } ) ;
541+
542+ const responses = [ ...response1 , ...response2 ] ;
543+ expect ( responses ) . to . have . lengthOf ( 2 ) ;
544+ expect ( responses [ 0 ] . txHash ) . to . be . a ( "string" ) . and . not . empty ;
545+ expect ( responses [ 1 ] . txHash ) . to . be . a ( "string" ) . and . not . empty ;
546+ } ) ;
547+
548+ it ( "should fail when trying to tag with invalid dispute ID" , async ( ) => {
549+ await expect (
550+ clientA . dispute . tagIfRelatedIpInfringed ( {
551+ infringementTags : [
552+ {
553+ ipId : childIpId ,
554+ disputeId : 999999n ,
555+ } ,
556+ ] ,
557+ txOptions : { waitForTransaction : true } ,
558+ } ) ,
559+ ) . to . be . rejected ;
560+ } ) ;
561+
339562 it ( "should resolve a dispute successfully when initiated by dispute initiator" , async ( ) => {
563+ // First set judgment
564+ const { request } = await publicClient . simulateContract ( {
565+ address : DISPUTE_MODULE_ADDRESS ,
566+ abi : [ SET_DISPUTE_JUDGEMENT_ABI ] ,
567+ functionName : "setDisputeJudgement" ,
568+ args : [ disputeId , true , "0x" ] ,
569+ account : judgeWalletClient . account ! ,
570+ } ) ;
571+ const judgmentTxHash = await judgeWalletClient . writeContract ( request ) ;
572+ await publicClient . waitForTransactionReceipt ( { hash : judgmentTxHash } ) ;
573+
574+ const disputeState = await publicClient . readContract ( {
575+ address : disputeModuleAddress [ aeneid ] ,
576+ abi : disputeModuleAbi ,
577+ functionName : "disputes" ,
578+ args : [ disputeId ] ,
579+ } ) ;
580+ expect ( disputeState [ 6 ] ) . to . equal ( disputeState [ 5 ] ) ;
581+
340582 const response = await clientA . dispute . resolveDispute ( {
341583 disputeId : disputeId ,
342584 data : "0x" ,
@@ -347,7 +589,6 @@ describe("Dispute Functions", () => {
347589 expect ( response . txHash ) . to . be . a ( "string" ) . and . not . empty ;
348590 } ) ;
349591
350- // Test that non-initiators cannot resolve the dispute
351592 it ( "should fail when non-initiator tries to resolve the dispute" , async ( ) => {
352593 await expect (
353594 clientB . dispute . resolveDispute ( {
0 commit comments