@@ -223,9 +223,11 @@ type Chain struct {
223223 validatorAPIClients validatorAPIClients
224224
225225 feeTokenInstrument splice_api_token_holding_v1.InstrumentId
226+ feeAmountPerMessage uint64 // per-message fee budget; used when rotating fee holdings after send
226227 nextFeeCID string // holding CID to be used as fee on next message send
227228 transferTokenInstrument * splice_api_token_holding_v1.InstrumentId
228229 nextTransferCID string // holding CID to be used as transfer on next message send
230+ sendsLeft uint64 // remaining sends in current setup batch; 0 = always rotate
229231
230232 // verifierObs is injected post-construction by test runners (see SetVerifierObservation).
231233 // Required by ConfirmExecOnDest to fetch verifier results from aggregator/indexer.
@@ -1072,9 +1074,12 @@ func (c *Chain) SetupSend(
10721074 }
10731075
10741076 c .feeTokenInstrument = feeTokenInstrument
1077+ c .feeAmountPerMessage = feeAmountPerMessage
10751078 c .nextFeeCID = selectedFee [0 ].ContractID
10761079
10771080 if transferAmountPerMessage == nil || transferAmountPerMessage .Sign () <= 0 {
1081+ c .transferTokenInstrument = nil
1082+ c .nextTransferCID = ""
10781083 return nil
10791084 }
10801085
@@ -1103,6 +1108,17 @@ func (c *Chain) SetupSend(
11031108 return nil
11041109}
11051110
1111+ // SetSequentialSends limits holding rotation to the next sends messages in this setup batch.
1112+ // After the send whose on-chain seq equals nextSeq+sends, setNextHoldings is skipped.
1113+ // Pass 0 to always rotate (open-ended load).
1114+ func (c * Chain ) SetSequentialSends (sends int ) {
1115+ if sends <= 0 {
1116+ c .sendsLeft = 0
1117+ return
1118+ }
1119+ c .sendsLeft = uint64 (sends )
1120+ }
1121+
11061122// MintTokens mint tokens for transfer and fees. To be used on devenv tests only.
11071123// this method won't work in staging/prod tests
11081124func (c * Chain ) MintTokens (ctx context.Context , amount * big.Rat ) error {
@@ -1440,16 +1456,6 @@ func (c *Chain) SendMessage(ctx context.Context, dest uint64, fields cciptestint
14401456 Uint64 ("seqNo" , parsedSend .seqNo ).
14411457 Msg ("CCIP Send executed" )
14421458
1443- // Set next holdings
1444- var tokenAmount * big.Rat
1445- if hasTokenTransfer {
1446- tokenAmount = new (big.Rat ).SetFrac (fields .TokenAmount .Amount , big .NewInt (CantonFixedPointScale ))
1447- }
1448- err = c .setNextHoldings (update .GetTransaction ().GetEvents (), hasTokenTransfer , tokenAmount )
1449- if err != nil {
1450- return cciptestinterfaces.MessageSentEvent {}, fmt .Errorf ("set next holdings: %w" , err )
1451- }
1452-
14531459 event := cciptestinterfaces.MessageSentEvent {
14541460 MessageID : parsedSend .messageID ,
14551461 ReceiptIssuers : nil , // TODO: add them later, not currently needed
@@ -1462,6 +1468,24 @@ func (c *Chain) SendMessage(ctx context.Context, dest uint64, fields cciptestint
14621468 c .lastSentSeq = parsedSend .seqNo
14631469 c .lastSentEvent = event
14641470
1471+ c .sendsLeft --
1472+ if c .sendsLeft == 0 {
1473+ c .logger .Info ().
1474+ Uint64 ("sendsLeft" , c .sendsLeft ).
1475+ Msg ("Skipping holding rotation after last planned send in batch" )
1476+
1477+ return event , nil
1478+ }
1479+
1480+ var tokenAmount * big.Rat
1481+ if hasTokenTransfer {
1482+ tokenAmount = new (big.Rat ).SetFrac (fields .TokenAmount .Amount , big .NewInt (CantonFixedPointScale ))
1483+ }
1484+ err = c .setNextHoldings (update .GetTransaction ().GetEvents (), hasTokenTransfer , tokenAmount )
1485+ if err != nil {
1486+ return cciptestinterfaces.MessageSentEvent {}, fmt .Errorf ("set next holdings: %w" , err )
1487+ }
1488+
14651489 return event , nil
14661490}
14671491
@@ -1590,10 +1614,11 @@ func (c *Chain) setNextHoldings(events []*apiv2.Event, hasTokenTransfer bool, to
15901614 testhelpers .ExcludeCIDs (spentCIDs ),
15911615 }
15921616
1617+ feeMin := new (big.Rat ).SetUint64 (c .feeAmountPerMessage )
15931618 nextFeeCID , exhaustion , err := pickNextHolding (
15941619 events ,
15951620 c .feeTokenInstrument ,
1596- big . NewRat ( 0 , 1 ), // TODO: we'll have to consider real fee here once we go load tests
1621+ feeMin ,
15971622 refreshFilters ... ,
15981623 )
15991624 if err != nil && ! exhaustion {
0 commit comments