Skip to content

Conversation

@andrevmatos
Copy link
Collaborator

@andrevmatos andrevmatos commented Jan 10, 2026

  • RequestMessage type is exported, and is a relaxed version of AnyMessage, which requires only receiver, and replaces it in the exported types
  • It's accepted in getFee, generateUnsignedSendMessage and sendMessage
  • A new static method, Chain.buildMessageForDest, is able to convert a RequestMessage into stricter AnyMessage (needed by Router.ccipSend) by populating default values where they make sense, specially for extraArgs
    • e.g. gasLimit, tokenReceiver, etc
    • it's destination-aware, while the default implementation emits GenericExtraArgsV2 (for EVM, Aptos, TON)
    • Solana & Sui have their own specialization, emitting the respective ExtraArgs
  • Should supersede feat(sdk): add simplified token transfer API #96 with a smaller interface area
  • This allows the simplified token transfer interface we aim from the existing methods:
await chain.sendMessage({
  router,
  destChainSelector,
  message: {
    receiver,
    tokenAmounts: [{ token, amount }]
  },
  wallet,
})

@andrevmatos andrevmatos self-assigned this Jan 10, 2026
@andrevmatos andrevmatos requested a review from a team as a code owner January 10, 2026 04:53
@vercel
Copy link

vercel bot commented Jan 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
ccip-tools-ts Error Error Jan 12, 2026 5:09pm

@github-actions
Copy link

👋 andrevmatos, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions
Copy link

github-actions bot commented Jan 10, 2026

Coverage Report

ℹ tests 675
ℹ suites 206
ℹ pass 675
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 180246.209645
-------------------------------|---------|----------|---------|---------|---------------------------
File                           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s         
-------------------------------|---------|----------|---------|---------|---------------------------
All files                      |   67.03 |    80.78 |    56.4 |   67.03 |                           
 ccip-cli/src                  |   86.45 |    83.33 |      50 |   86.45 |                           
  index.ts                     |   86.45 |    83.33 |      50 |   86.45 | 72-76,82-83,88-93         
 ccip-cli/src/commands         |   53.68 |    79.44 |   55.55 |   53.68 |                           
  index.ts                     |     100 |      100 |     100 |     100 |                           
  lane-latency.ts              |   67.74 |     87.5 |   33.33 |   67.74 | 23-37,44-51,85-91         
  manual-exec.ts               |      21 |      100 |       0 |      21 | 42-106,113-123,125-236    
  parse.ts                     |   41.79 |      100 |       0 |   41.79 | 22-26,33-40,42-67         
  send.ts                      |   12.38 |      100 |       0 |   12.38 | 34-136,143-150,152-323    
  show.ts                      |   89.61 |    63.82 |      60 |   89.61 | ...23-129,135-137,146-147 
  supported-tokens.ts          |   23.48 |      100 |       0 |   23.48 | ...83-175,177-232,234-247 
  types.ts                     |     100 |      100 |     100 |     100 |                           
  utils.ts                     |   86.59 |    84.03 |    91.3 |   86.59 | ...99-517,524-532,542-548 
 ccip-cli/src/providers        |   53.94 |    75.51 |   17.39 |   53.94 |                           
  aptos.ts                     |   53.65 |      100 |       0 |   53.65 | ...70,78-85,91-92,101-123 
  evm.ts                       |   46.03 |      100 |       0 |   46.03 | 20,31-63                  
  index.ts                     |   82.95 |    72.72 |      80 |   82.95 | 49-50,188-223             
  solana.ts                    |   50.42 |      100 |       0 |   50.42 | ...-71,79-85,89-90,99-117 
  sui.ts                       |   64.28 |      100 |       0 |   64.28 | 10-14                     
  ton.ts                       |   14.58 |      100 |       0 |   14.58 | 22-144                    
 ccip-sdk/src                  |   93.26 |       89 |   91.52 |   93.26 |                           
  chain.ts                     |   92.91 |     86.2 |      75 |   92.91 | ...32,251-289,577,635-644 
  commits.ts                   |     100 |       90 |     100 |     100 | 35,52                     
  execution.ts                 |   84.61 |      100 |      75 |   84.61 | 122-143                   
  explorer.ts                  |     100 |      100 |     100 |     100 |                           
  extra-args.ts                |     100 |    85.71 |     100 |     100 | 71,90                     
  gas.ts                       |   96.42 |    92.85 |     100 |   96.42 | 81-85                     
  http-status.ts               |     100 |      100 |     100 |     100 |                           
  index.ts                     |     100 |      100 |     100 |     100 |                           
  offchain.ts                  |     100 |      100 |     100 |     100 |                           
  requests.ts                  |   78.84 |    76.92 |      75 |   78.84 | ...14-315,319-320,343-364 
  supported-chains.ts          |     100 |      100 |     100 |     100 |                           
  types.ts                     |     100 |      100 |     100 |     100 |                           
  utils.ts                     |   95.11 |    90.81 |     100 |   95.11 | ...51,515-516,532,597-605 
 ccip-sdk/src/api              |     100 |    94.73 |     100 |     100 |                           
  index.ts                     |     100 |    94.73 |     100 |     100 | 145                       
 ccip-sdk/src/aptos            |   57.89 |    69.65 |      60 |   57.89 |                           
  exec.ts                      |   29.31 |      100 |       0 |   29.31 | 18-58                     
  hasher.ts                    |   76.31 |       80 |   66.66 |   76.31 | 19-38,52-58               
  index.ts                     |   58.91 |    73.49 |   62.22 |   58.91 | ...16-751,755-848,852-863 
  logs.ts                      |   78.52 |    57.44 |      75 |   78.52 | ...90-196,200-233,264-268 
  send.ts                      |    25.2 |      100 |       0 |    25.2 | 10-51,62-79,92-123        
  token.ts                     |   23.75 |       75 |     100 |   23.75 | 35-156                    
  types.ts                     |   69.72 |      100 |       0 |   69.72 | 25-32,77-101              
  utils.ts                     |     100 |      100 |     100 |     100 |                           
 ccip-sdk/src/errors           |   80.94 |    76.61 |   49.55 |   80.94 |                           
  CCIPError.ts                 |     100 |      100 |     100 |     100 |                           
  codes.ts                     |     100 |      100 |     100 |     100 |                           
  index.ts                     |     100 |      100 |     100 |     100 |                           
  recovery.ts                  |     100 |      100 |     100 |     100 |                           
  specialized.ts               |   73.21 |    71.91 |   46.72 |   73.21 | ...39,1647-1656,1664-1673 
  utils.ts                     |   94.52 |    77.77 |     100 |   94.52 | 16,18,23,25               
 ccip-sdk/src/evm              |   64.83 |    78.82 |   62.85 |   64.83 |                           
  const.ts                     |     100 |      100 |     100 |     100 |                           
  errors.ts                    |   82.48 |    78.46 |     100 |   82.48 | ...55-157,188-195,198-216 
  hasher.ts                    |     100 |     87.5 |     100 |     100 | 122                       
  index.ts                     |   58.45 |    84.61 |   58.49 |   58.45 | ...21,1325-1398,1402-1451 
  logs.ts                      |   33.99 |    46.66 |      25 |   33.99 | ...13-214,229-258,274-302 
  messages.ts                  |     100 |      100 |     100 |     100 |                           
  offchain.ts                  |    80.4 |    53.33 |      75 |    80.4 | ...45-147,151-165,191-196 
 ccip-sdk/src/evm/viem         |   77.72 |       92 |   69.23 |   77.72 |                           
  client-adapter.ts            |     100 |     92.3 |     100 |     100 | 48                        
  index.ts                     |     100 |      100 |     100 |     100 |                           
  wallet-adapter.ts            |   63.09 |     90.9 |   55.55 |   63.09 | ...6,53-73,91-124,131-157 
 ccip-sdk/src/hasher           |   94.29 |    78.94 |     100 |   94.29 |                           
  common.ts                    |     100 |      100 |     100 |     100 |                           
  hasher.ts                    |     100 |    66.66 |     100 |     100 | 19                        
  index.ts                     |     100 |      100 |     100 |     100 |                           
  merklemulti.ts               |   93.43 |       78 |     100 |   93.43 | ...59-260,306-307,315-316 
 ccip-sdk/src/solana           |   52.43 |     70.1 |   56.32 |   52.43 |                           
  cleanup.ts                   |   12.22 |      100 |       0 |   12.22 | 29-229                    
  exec.ts                      |    9.27 |      100 |       0 |    9.27 | ...66-341,343-382,384-496 
  hasher.ts                    |   96.58 |    81.81 |     100 |   96.58 | 67-70                     
  index.ts                     |   71.47 |    76.11 |   64.81 |   71.47 | ...33,1437-1461,1465-1486 
  logs.ts                      |   74.19 |    27.27 |     100 |   74.19 | ...,50-51,53-54,56-88,119 
  offchain.ts                  |   78.87 |     64.7 |      50 |   78.87 | ...,96-97,110-111,126-142 
  patchBorsh.ts                |   65.06 |    57.14 |      75 |   65.06 | 30-49,65-66,72-78         
  send.ts                      |   14.84 |      100 |       0 |   14.84 | ...63-252,265-331,333-384 
  types.ts                     |   74.46 |      100 |       0 |   74.46 | 36-47                     
  utils.ts                     |   54.14 |    77.77 |      60 |   54.14 | ...71-284,326-389,395-410 
 ccip-sdk/src/sui              |   33.42 |    93.47 |   14.54 |   33.42 |                           
  discovery.ts                 |   16.56 |      100 |       0 |   16.56 | 18-34,44-157              
  events.ts                    |   30.21 |      100 |       0 |   30.21 | ...83-154,199-288,296-321 
  hasher.ts                    |   98.16 |    66.66 |     100 |   98.16 | 33,49                     
  index.ts                     |   38.63 |      100 |   12.19 |   38.63 | ...19-720,724-725,729-730 
  objects.ts                   |   12.77 |      100 |       0 |   12.77 | ...05-146,157-207,218-360 
 ccip-sdk/src/sui/manuallyExec |   39.46 |      100 |       0 |   39.46 |                           
  encoder.ts                   |   47.67 |      100 |       0 |   47.67 | 42-86                     
  index.ts                     |    34.3 |      100 |       0 |    34.3 | 48-137                    
 ccip-sdk/src/ton              |   88.26 |    87.64 |   73.52 |   88.26 |                           
  exec.ts                      |     100 |      100 |     100 |     100 |                           
  hasher.ts                    |   77.95 |    77.77 |      75 |   77.95 | 99-107,155-186            
  index.ts                     |   94.09 |    88.78 |   67.39 |   94.09 | ...56,1060-1061,1065-1066 
  logs.ts                      |     100 |    98.52 |     100 |     100 | 56                        
  types.ts                     |   78.41 |    69.23 |   66.66 |   78.41 | ...-76,94,121-134,136-139 
  utils.ts                     |   75.98 |       75 |     100 |   75.98 | ...55-261,273-327,329-332 
-------------------------------|---------|----------|---------|---------|---------------------------

data: hexlify(message_.data ?? '0x'),
tokenAmounts: message.tokenAmounts ?? [],
feeToken: message.feeToken ?? ZeroAddress,
extraArgs: hexlify((this.constructor as typeof EVMChain).encodeExtraArgs(message.extraArgs)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
extraArgs: hexlify((this.constructor as typeof EVMChain).encodeExtraArgs(message.extraArgs)),
extraArgs: hexlify((this.constructor as typeof EVMChain).encodeExtraArgs(_message.extraArgs)),

Should be _message instead?

PabloMansanet
PabloMansanet previously approved these changes Jan 12, 2026
Copy link
Contributor

@PabloMansanet PabloMansanet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM in terms of behaviour (once the bug found by Amine is addressed) though I have some concerns on readability and naming.

I think this feels like a common builder pattern where the interface accepts both the built product and the builder itself (to then supply defaults) so I would leverage the users familiarity with the concept of builders to make the interfaces easier to read.

There's also some naming in the implementations that could use some work (e.g. message_ vs message is error prone, compared to populatedMessage vs message or, if you go with my original suggestion, message vs messageBuilder.

Overall not a merge-blocker but I'd like your take on the naming options 👍

describe: "Address of the Solana tokenReceiver (if different than program's receiver)",
},
account: {
alias: 'receiver-object-id',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the benefit of aliasing instead of having a separate optional argument? receiverObjectIds seem conceptually pretty different to solana accounts so maybe it's a bit cleaner to split it (no strong opinion though).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From CLI's perspective, it's not different: each is an array of address, and they're mutually exclusive (either you're sending to Solana and populating accounts, or you're sending to Sui and populating receiverObjectIds in extraArgs; they also serve semantically the same purpose: a list of dependent addresses needed for the receiver callback in dest;

it's inevitable to expose them a little in order to allow them to pass important specific parameters like these, which we (ccip-tools-ts) can't derive/guess for them, but my idea here is to make it as cross-compatible as possible

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, happy to keep as-is.

message,
}: Parameters<Chain['getFee']>[0]): Promise<bigint> {
return getFee(this.provider, router, destChainSelector, message)
const message_ = populateDefaultMessageForDest(message, networkInfo(destChainSelector).family)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const message_ = populateDefaultMessageForDest(message, networkInfo(destChainSelector).family)
const populatedMessage = populateDefaultMessageForDest(message, networkInfo(destChainSelector).family)

NIT: I think being explicit here helps readability (this applies elsewhere in this PR)

destChainSelector,
message,
}: Parameters<Chain['getFee']>[0]): Promise<bigint> {
const message_ = populateDefaultMessageForDest(message, networkInfo(destChainSelector).family)
Copy link
Contributor

@PabloMansanet PabloMansanet Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mixing message_ and message in this function feels error-prone and a bit confusing. I'd rename message to populatedMessage and be consistent in only using populatedMessage after this point, as it's a superset of message anyway, which saves the reader from having to think whether message is still OK to use or not.

Even better (for me) would be to go with the builder naming (message vs messageBuilder), I'll talk more about that later.

* @param message - AnyMessage (from source), containing at least `receiver`
* @returns A message suitable for `sendMessage` to this destination chain family
*/
populateDefaultMessageForDest(message: RequestMessage): AnyMessage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads to me like a builder pattern. WDYT about renaming this to something like:

Suggested change
populateDefaultMessageForDest(message: RequestMessage): AnyMessage
BuildMessageForDest(builder: MessageBuilder): AnyMessage

I ask because I find RequestMessage a bit strange in terms of naming. Am I requesting a message? Is it a message request? To whom?

Things like the send API could take a parameter of type message: AnyMessage | MessageBuilder to make it obvious they can supply defaults if needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agree with the renaming, if it makes things clearer

…Args

this function populates a partial message (`RequestMessage` type is
exported and replaces stricter `AnyMesssage`) with default extraArgs and
massage other parameters; it allows sending a simple token transfer by
just calling: `chain.sendMessage({router, dest, message: { receiver,
tokenAmounts: [{ token, amount}] }})`
@andrevmatos andrevmatos changed the title implement Chain.populateDefaultMessageForDest and allow partial extraArgs implement Chain.buildMessageForDest and allow partial extraArgs Jan 12, 2026
@andrevmatos andrevmatos merged commit 90cede0 into main Jan 12, 2026
10 of 11 checks passed
@andrevmatos andrevmatos deleted the feat/token-transfer2 branch January 12, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants