Skip to content

feat(sdk): support tokens without the optional ERC-20 decimals() view via pool-declared and family-default decimals - #504

Merged
andrevmatos merged 4 commits into
mainfrom
feat/token-decimals-fallbacks
Oct 23, 2026
Merged

andrevmatos merged 4 commits into
mainfrom
feat/token-decimals-fallbacks

Conversation

@SyedAsadKazmi

@SyedAsadKazmi SyedAsadKazmi commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Support tokens without the optional ERC-20 decimals() view

decimals() is optional in ERC-20. Tokens that skip it used to crash the CLI with a raw provider error (Failed to call "decimals") and the SDK had no way to resolve their decimals.

Decimals now resolve per side with the same fallback chain, all internal: the token's own view first, then the pool's getTokenDecimals() (pool v1.5.1+, which is what the pool itself uses for conversion), then the chain family's static default for preflight conversions. For the actual transfer amount nothing is guessed: if neither the token nor its pool can declare them, the send fails with TOKEN_DECIMALS_UNAVAILABLE. In most cases a plain token=amount just works now, no decimals input needed.

SDK

  • EVMChain.getTokenInfo throws the new typed CCIPTokenDecimalsUnavailableError (TOKEN_DECIMALS_UNAVAILABLE, with recovery hint) for the recognized unavailable cases (a revert, or a return that can't decode) instead of the raw provider error. Transport failures (TIMEOUT, NETWORK_ERROR, ...) keep their own codes so retry handling still sees them. name() is best effort since it's optional too.
  • getTokenPoolConfig exposes the pool's declared decimals as a new optional decimals field (v1.5.1+ pools). v1.5.0 pools predate the getter and stay readable without it; a transport failure on the getter propagates instead of silently reading as "no decimals".
  • New resolveTokenDecimals helper holds the fallback chain in one place: token view, then pool-declared decimals, then the family's static default (ChainStatic.decimals, e.g. 18 on EVM). The family default is preflight-only; familyDefault: false opts out where the decimals determine the actual transfer amount. The pool is resolved lazily: a resolver with nothing to resolve from returns undefined and falls through, a lookup failure propagates.
  • Destination preflights (estimateReceiveExecution, getRequiredCCVs, both checkExecute layers) and getDestTokenAmount use it on both sides. getDestTokenAmount resolves the dest pool through the destination TokenAdminRegistry via the offRamp, the same way checkExecute does, so conversion and execution use the same pool. Both EVMChain.estimateReceiveExecution overloads (messageId lookup and direct) pass the offRamp through, so direct estimation converts via the registered pool too. It no longer reads source-token metadata directly when extraData is absent. Pool-generated extraData (the source pool's destPoolData from lockOrBurn) stays the automatic path.
  • No new chain method and no caller-supplied decimals fields. tokenAmounts entries keep their original shape.

CLI

  • send --transfer-tokens stays plain token=amount. Source decimals resolve token, then source pool (via the router's registry), all inside parseTokenAmounts. No family default here: these decimals set the actual transfer amount, so a lookup failure (e.g. a registry timeout) surfaces instead of silently parsing at a guessed precision.
  • Token display falls back to raw units so a successful send is still printable.

Docs

CLI send page (Token Amount Format), troubleshooting entry, SDK querying-data note, error-reference row. README and CHANGELOG updated.

Testing

New tests for getTokenInfo and the getTokenPoolConfig decimals field (stubbed eth_call), parseTokenAmounts fallbacks including a registry-timeout regression, the getDestTokenAmount/checkExecute pool and family-default fallbacks on both sides, a registered-pool-vs-stale-remote-pool regression, a direct-estimation regression asserting the converted balance override, and timeout propagation on every resolution path. 4017/4017 unit tests, npm run check green. Also verified by hand against a live Sepolia token without decimals(): two sends to Fuji with plain token=amount, both quoted the same fee and executed on destination.

@SyedAsadKazmi
SyedAsadKazmi requested review from a team as code owners October 18, 2026 16:29
@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
ccip-tools-ts Ready Ready Preview Oct 22, 2026 5:11pm UTC

Request Review

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

CI Test Report

✅ 4306/4306 tests passed (1088 suites) in 5m 56s

Summary

ℹ tests 4306
ℹ suites 1088
ℹ pass 4306
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 356395.709042
Coverage report
File                                   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------------------------------|---------|----------|---------|---------|-------------------
All files                              |   87.84 |     84.2 |   80.32 |   87.84 |                   
 ccip-cli/src                          |   93.78 |    86.13 |   88.46 |   93.78 |                   
  chain-selectors.ts                   |   98.14 |    90.22 |     100 |   98.14 | ...33-134,285-287 
  index.ts                             |   87.44 |    60.71 |   66.66 |   87.44 | ...05-209,215-220 
 ccip-cli/src/commands                 |   54.31 |    78.65 |   65.07 |   54.31 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  lane-latency.ts                      |   70.76 |    83.33 |   33.33 |   70.76 | ...,76-83,119-128 
  lane.ts                              |   86.98 |    68.42 |     100 |   86.98 | ...41-144,148-150 
  manual-exec.ts                       |   20.45 |      100 |       0 |   20.45 | ...42-152,154-350 
  parse.ts                             |    55.2 |      100 |       0 |    55.2 | 47-51,58-65,67-96 
  search.ts                            |   81.25 |      100 |       0 |   81.25 | 24-29             
  send.ts                              |   14.23 |      100 |       0 |   14.23 | ...08-236,238-548 
  show.ts                              |    75.8 |    63.75 |     100 |    75.8 | ...17-320,401-403 
  supported-tokens.ts                  |   17.93 |      100 |       0 |   17.93 | ...80-353,355-368 
  token.ts                             |   22.72 |      100 |       0 |   22.72 | ...3,60-67,69-132 
  types.ts                             |     100 |      100 |     100 |     100 |                   
  utils.ts                             |   91.69 |    84.21 |     100 |   91.69 | ...14,720,722-732 
 ccip-cli/src/commands/search          |   53.89 |    76.19 |    12.5 |   53.89 |                   
  messages.ts                          |   53.89 |    76.19 |    12.5 |   53.89 | ...36-258,260-295 
 ccip-cli/src/providers                |   58.44 |    79.45 |   28.26 |   58.44 |                   
  aptos.ts                             |   51.47 |      100 |       0 |   51.47 | ...,95-96,105-136 
  evm.ts                               |   72.25 |    63.63 |      75 |   72.25 | ...34,137-149,169 
  index.ts                             |    80.9 |    83.48 |    90.9 |    80.9 | ...70,332,392-440 
  solana.ts                            |   44.89 |      100 |       0 |   44.89 | ...12-113,122-147 
  sui.ts                               |    49.5 |      100 |       0 |    49.5 | ...57-258,267-301 
  ton.ts                               |   15.03 |      100 |       0 |   15.03 | 24-153            
 ccip-cli/src/providers/canton         |   69.57 |     76.4 |   45.71 |   69.57 |                   
  auth.ts                              |   82.41 |    73.01 |   53.33 |   82.41 | ...17-333,464-469 
  config.ts                            |   75.64 |       75 |     100 |   75.64 | 36-43,48-58       
  index.ts                             |     100 |      100 |     100 |     100 |                   
  wallet.ts                            |   53.09 |      100 |   33.33 |   53.09 | ...58-260,411-452 
 ccip-cli/src/verifiers                |   82.26 |    90.47 |   33.33 |   82.26 |                   
  grpc-transport.ts                    |     100 |       90 |   66.66 |     100 | 48,57             
  options.ts                           |   62.12 |      100 |       0 |   62.12 | 12-20,34-37,52-63 
 ccip-sdk/src                          |   96.04 |    89.48 |   94.25 |   96.04 |                   
  all-chains.ts                        |     100 |      100 |     100 |     100 |                   
  chain.ts                             |   97.36 |    85.95 |   86.48 |   97.36 | ...2618,2651-2652 
  commits.ts                           |   97.01 |       92 |     100 |   97.01 | 104-111,193-194   
  execution.ts                         |   86.26 |    79.31 |     100 |   86.26 | ...79-186,192-199 
  explorer.ts                          |     100 |      100 |     100 |     100 |                   
  extra-args.ts                        |     100 |    91.17 |     100 |     100 | 258,287,302       
  fetch.ts                             |   97.94 |    93.99 |   97.95 |   97.94 | ...1007,1253-1255 
  gas.ts                               |   85.92 |    84.78 |      75 |   85.92 | ...01-312,427-476 
  http-status.ts                       |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  messages.ts                          |   80.28 |    52.54 |   57.14 |   80.28 | ...17-328,332-345 
  networks.ts                          |     100 |      100 |     100 |     100 |                   
  offchain.ts                          |   84.64 |    76.92 |     100 |   84.64 | ...18-227,236-237 
  requests.ts                          |   96.77 |    90.05 |     100 |   96.77 | ...72-673,698-703 
  supported-chains.ts                  |     100 |       90 |     100 |     100 | 33-34             
  types.ts                             |     100 |      100 |     100 |     100 |                   
  utils.ts                             |   99.59 |    96.51 |     100 |   99.59 | 212-213,215       
 ccip-sdk/src/api                      |   93.56 |    83.33 |   95.23 |   93.56 |                   
  index.ts                             |   93.56 |    83.33 |   95.23 |   93.56 | ...73-876,929-958 
 ccip-sdk/src/aptos                    |   72.59 |    75.57 |    63.8 |   72.59 |                   
  exec.ts                              |   29.31 |      100 |       0 |   29.31 | 18-58             
  hasher.ts                            |   75.89 |       80 |   66.66 |   75.89 | 17-36,50-56       
  index.ts                             |   54.68 |    78.31 |   41.86 |   54.68 | ...1094,1098-1109 
  logs.ts                              |   95.09 |    74.76 |   90.38 |   95.09 | ...1442-1444,1731 
  send.ts                              |    25.6 |      100 |       0 |    25.6 | ...2,63-80,93-125 
  token.ts                             |     7.5 |      100 |       0 |     7.5 | 13-160            
  types.ts                             |   65.97 |      100 |       0 |   65.97 | 26-33,65-89       
 ccip-sdk/src/canton                   |   55.61 |     74.3 |   51.02 |   55.61 |                   
  addressCodec.ts                      |   95.12 |    95.38 |   91.66 |   95.12 | ...69-176,277-280 
  amount.ts                            |   92.59 |       70 |     100 |   92.59 | 22-23             
  ccv-addresses.ts                     |   96.99 |    79.16 |     100 |   96.99 | 19-20,22,29       
  defaults.ts                          |   99.21 |     92.3 |     100 |   99.21 | 90                
  events.ts                            |    54.4 |    68.08 |    42.1 |    54.4 | ...52-564,570-579 
  index.ts                             |   39.08 |    48.38 |   19.17 |   39.08 | ...2651,2654-2656 
  networks.ts                          |     100 |      100 |     100 |     100 |                   
  submit-commands.ts                   |   87.58 |       60 |     100 |   87.58 | ...95,123-127,134 
  types.ts                             |     100 |      100 |     100 |     100 |                   
  update-id.ts                         |   98.11 |    88.88 |     100 |   98.11 | 52                
 ccip-sdk/src/canton/authentication    |   93.05 |    79.31 |    92.3 |   93.05 |                   
  authorization-code.ts                |   89.83 |    84.31 |    90.9 |   89.83 | ...58-376,432-443 
  client-credentials.ts                |   91.28 |       75 |     100 |   91.28 | ...92-196,198-202 
  index.ts                             |    96.8 |       75 |     100 |    96.8 | 168-173           
  metadata.ts                          |   81.89 |    44.44 |      50 |   81.89 | ...55,73-78,93-94 
  static.ts                            |     100 |      100 |     100 |     100 |                   
  token-source.ts                      |   98.88 |    77.77 |     100 |   98.88 | 165-166           
  types.ts                             |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/canton/client            |    70.8 |    70.49 |   44.73 |    70.8 |                   
  client.ts                            |   69.71 |       70 |   44.73 |   69.71 | ...28-829,832-833 
  index.ts                             |     100 |      100 |     100 |     100 |                   
 ...dk/src/canton/explicit-disclosures |   72.01 |    67.74 |   53.19 |   72.01 |                   
  acs.ts                               |   87.42 |    67.47 |   89.28 |   87.42 | ...53,574,609-610 
  eds.ts                               |   51.12 |      100 |       0 |   51.12 | ...70-477,481-486 
 ccip-sdk/src/canton/token-metadata    |   59.52 |      100 |       0 |   59.52 |                   
  client.ts                            |   59.52 |      100 |       0 |   59.52 | 120-199,206-210   
 ...dk/src/canton/transfer-instruction |   50.63 |      100 |       0 |   50.63 |                   
  client.ts                            |   50.63 |      100 |       0 |   50.63 | 114-224,231-235   
 ccip-sdk/src/cct                      |     100 |    98.38 |     100 |     100 |                   
  errors.ts                            |     100 |      100 |     100 |     100 |                   
  operation.ts                         |     100 |      100 |     100 |     100 |                   
  query.ts                             |     100 |      100 |     100 |     100 |                   
  remote-address.ts                    |     100 |    95.45 |     100 |     100 | 80                
  token-manager.ts                     |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/canton               |   68.04 |    69.84 |   53.33 |   68.04 |                   
  encoding.ts                          |   98.24 |       75 |     100 |   98.24 | 53                
  gateway.test.helpers.ts              |   20.79 |       50 |       0 |   20.79 | ...90-133,143-226 
  index.ts                             |   90.11 |      100 |   54.54 |   90.11 | ...16-119,123-126 
  operation.ts                         |   88.55 |    55.55 |      75 |   88.55 | ...20-124,155-166 
  query.ts                             |     100 |      100 |     100 |     100 |                   
  validate.ts                          |   75.19 |    70.37 |     100 |   75.19 | ...19-124,126-127 
 ...rc/cct/canton/token-admin-registry |   86.36 |    79.16 |     100 |   86.36 |                   
  shared.ts                            |   86.36 |    79.16 |     100 |   86.36 | 125-139,147-152   
 ...on/token-admin-registry/operations |   98.94 |    82.14 |     100 |   98.94 |                   
  get-token-admin-registry.ts          |   98.88 |    81.48 |     100 |   98.88 | 133,178           
  index.ts                             |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/canton/token-pool    |   88.09 |     92.3 |   82.35 |   88.09 |                   
  shared.ts                            |   88.09 |     92.3 |   82.35 |   88.09 | ...51-368,529-530 
 ...c/cct/canton/token-pool/operations |   91.23 |    70.86 |   96.77 |   91.23 |                   
  apply-chain-updates.ts               |   78.63 |    78.57 |      75 |   78.63 | ...35-140,220-233 
  deploy-token-pool.ts                 |   92.59 |    71.79 |     100 |   92.59 | ...97-202,204-209 
  get-rate-limiter-state.ts            |   96.68 |    79.31 |     100 |   96.68 | 75-80             
  get-token-pool-state.ts              |   94.94 |    61.11 |     100 |   94.94 | ...35,161,173,285 
  index.ts                             |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/evm                  |   94.15 |     96.4 |   37.72 |   94.15 |                   
  index.ts                             |   93.42 |      100 |   26.76 |   93.42 | ...4305,4320-4321 
  operation.ts                         |     100 |      100 |     100 |     100 |                   
  query.ts                             |     100 |      100 |     100 |     100 |                   
  submit.ts                            |     100 |    87.17 |     100 |     100 | 45,93,113-114,133 
  validate.ts                          |   97.65 |    97.67 |     100 |   97.65 | 99-103            
 ...dk/src/cct/evm/advanced-pool-hooks |     100 |     97.5 |     100 |     100 |                   
  contracts.ts                         |     100 |     97.5 |     100 |     100 | 255               
 ...evm/advanced-pool-hooks/operations |   99.01 |    98.05 |     100 |   99.01 |                   
  apply-ccv-config-updates.ts          |   94.32 |    90.47 |     100 |   94.32 | 81-84,101-104     
  deploy-advanced-pool-hooks.ts        |     100 |      100 |     100 |     100 |                   
  ...-pool-hooks-authorized-callers.ts |     100 |      100 |     100 |     100 |                   
  get-all-ccv-configs.ts               |     100 |      100 |     100 |     100 |                   
  get-ccv-config.ts                    |     100 |      100 |     100 |     100 |                   
  get-policy-engine.ts                 |     100 |      100 |     100 |     100 |                   
  get-required-ccvs.ts                 |     100 |      100 |     100 |     100 |                   
  get-threshold-amount.ts              |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  set-policy-engine.ts                 |     100 |      100 |     100 |     100 |                   
  set-threshold-amount.ts              |     100 |      100 |     100 |     100 |                   
  update-authorized-callers.ts         |     100 |      100 |     100 |     100 |                   
 .../cct/evm/artifacts/bytecode/V2_0_0 |     100 |      100 |     100 |     100 |                   
  advanced-pool-hooks.ts               |     100 |      100 |     100 |     100 |                   
  burn-from-mint-token-pool.ts         |     100 |      100 |     100 |     100 |                   
  burn-mint-token-pool.ts              |     100 |      100 |     100 |     100 |                   
  burn-with-from-mint-token-pool.ts    |     100 |      100 |     100 |     100 |                   
  cross-chain-token.ts                 |     100 |      100 |     100 |     100 |                   
  erc20-lockbox.ts                     |     100 |      100 |     100 |     100 |                   
  lock-release-token-pool.ts           |     100 |      100 |     100 |     100 |                   
  siloed-lock-release-token-pool.ts    |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/evm/lockbox          |     100 |    97.05 |     100 |     100 |                   
  contracts.ts                         |     100 |    97.05 |     100 |     100 | 97                
 ...sdk/src/cct/evm/lockbox/operations |     100 |      100 |     100 |     100 |                   
  deploy-lockbox.ts                    |     100 |      100 |     100 |     100 |                   
  deposit.ts                           |     100 |      100 |     100 |     100 |                   
  ...all-lockbox-authorized-callers.ts |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  update-authorized-callers.ts         |     100 |      100 |     100 |     100 |                   
  withdraw.ts                          |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/evm/token            |   99.36 |    87.69 |     100 |   99.36 |                   
  contracts.ts                         |   99.05 |    91.48 |     100 |   99.05 | 87-88,110         
  roles.ts                             |     100 |    77.77 |     100 |     100 | 55-61,80-86       
 ...k/src/cct/evm/token-admin-registry |     100 |      100 |     100 |     100 |                   
  contracts.ts                         |     100 |      100 |     100 |     100 |                   
 ...vm/token-admin-registry/operations |     100 |      100 |     100 |     100 |                   
  accept-admin.ts                      |     100 |      100 |     100 |     100 |                   
  get-supported-tokens.ts              |     100 |      100 |     100 |     100 |                   
  get-token-admin-registry.ts          |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  register-admin.ts                    |     100 |      100 |     100 |     100 |                   
  set-pool.ts                          |     100 |      100 |     100 |     100 |                   
  transfer-admin.ts                    |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/evm/token-pool       |     100 |    99.37 |     100 |     100 |                   
  contracts.ts                         |     100 |    99.21 |     100 |     100 | 677               
  rate-limit.ts                        |     100 |      100 |     100 |     100 |                   
  remote-pool.ts                       |     100 |      100 |     100 |     100 |                   
 ...sdk/src/cct/evm/token-pool-factory |   98.99 |    93.25 |     100 |   98.99 |                   
  contracts.ts                         |   93.27 |    85.71 |     100 |   93.27 | 68-75             
  deploy.ts                            |     100 |    93.54 |     100 |     100 | 331,334,336,393   
  predict.ts                           |     100 |       95 |     100 |     100 | 88                
 .../src/cct/evm/token-pool/operations |   99.76 |    96.88 |     100 |   99.76 |                   
  accept-pool-ownership.ts             |     100 |      100 |     100 |     100 |                   
  add-remote-pool.ts                   |     100 |      100 |     100 |     100 |                   
  apply-allowlist-updates.ts           |     100 |    96.87 |     100 |     100 | 232               
  apply-chain-updates.ts               |     100 |      100 |     100 |     100 |                   
  ...en-transfer-fee-config-updates.ts |   97.98 |    92.59 |     100 |   97.98 | 159-162           
  configure-siloed-lockboxes.ts        |     100 |      100 |     100 |     100 |                   
  deploy-token-pool.ts                 |     100 |     87.5 |     100 |     100 | 122-125           
  get-advanced-pool-hooks.ts           |     100 |      100 |     100 |     100 |                   
  get-all-siloed-lockbox-configs.ts    |     100 |      100 |     100 |     100 |                   
  get-allowed-finality-config.ts       |     100 |      100 |     100 |     100 |                   
  get-allowlist-enabled.ts             |     100 |      100 |     100 |     100 |                   
  get-allowlist.ts                     |     100 |      100 |     100 |     100 |                   
  get-available-tokens.ts              |     100 |    88.88 |     100 |     100 | 80                
  get-chain-rebalancer.ts              |     100 |      100 |     100 |     100 |                   
  get-dynamic-config.ts                |     100 |      100 |     100 |     100 |                   
  get-fee.ts                           |     100 |     90.9 |     100 |     100 | 56                
  get-lockbox.ts                       |     100 |      100 |     100 |     100 |                   
  get-rebalancer.ts                    |     100 |      100 |     100 |     100 |                   
  get-siloed-lockbox.ts                |     100 |    88.88 |     100 |     100 | 82                
  get-token-pool-remotes.ts            |     100 |      100 |     100 |     100 |                   
  get-token-pool-state.ts              |   98.61 |    95.23 |     100 |   98.61 | 283-286           
  get-token-transfer-fee-config.ts     |   94.79 |    57.14 |     100 |   94.79 | 63,66-69          
  index.ts                             |     100 |      100 |     100 |     100 |                   
  is-siloed.ts                         |     100 |      100 |     100 |     100 |                   
  provide-liquidity.ts                 |     100 |      100 |     100 |     100 |                   
  provide-siloed-liquidity.ts          |     100 |      100 |     100 |     100 |                   
  remove-remote-pool.ts                |     100 |      100 |     100 |     100 |                   
  set-allowed-finality-config.ts       |     100 |      100 |     100 |     100 |                   
  set-chain-rate-limiter-configs.ts    |     100 |    96.87 |     100 |     100 | 111               
  set-dynamic-config.ts                |     100 |      100 |     100 |     100 |                   
  set-rate-limit-admin.ts              |     100 |      100 |     100 |     100 |                   
  set-rebalancer.ts                    |     100 |      100 |     100 |     100 |                   
  set-remote-pool.ts                   |     100 |      100 |     100 |     100 |                   
  set-silo-rebalancer.ts               |     100 |      100 |     100 |     100 |                   
  transfer-liquidity.ts                |     100 |      100 |     100 |     100 |                   
  transfer-pool-ownership.ts           |     100 |      100 |     100 |     100 |                   
  update-advanced-pool-hooks.ts        |     100 |      100 |     100 |     100 |                   
  update-silo-designations.ts          |     100 |      100 |     100 |     100 |                   
  withdraw-fee-tokens.ts               |     100 |      100 |     100 |     100 |                   
  withdraw-liquidity.ts                |     100 |      100 |     100 |     100 |                   
  withdraw-siloed-liquidity.ts         |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/evm/token/operations |     100 |    99.42 |     100 |     100 |                   
  accept-default-admin-transfer.ts     |     100 |      100 |     100 |     100 |                   
  accept-token-ownership.ts            |     100 |      100 |     100 |     100 |                   
  approve-token.ts                     |     100 |      100 |     100 |     100 |                   
  begin-default-admin-transfer.ts      |     100 |      100 |     100 |     100 |                   
  cancel-default-admin-transfer.ts     |     100 |      100 |     100 |     100 |                   
  deploy-token.ts                      |     100 |      100 |     100 |     100 |                   
  get-burners.ts                       |     100 |      100 |     100 |     100 |                   
  get-ccip-admin.ts                    |     100 |      100 |     100 |     100 |                   
  get-minters.ts                       |     100 |      100 |     100 |     100 |                   
  get-token-default-admin.ts           |     100 |      100 |     100 |     100 |                   
  get-token-owner.ts                   |     100 |      100 |     100 |     100 |                   
  grant-burn-role.ts                   |     100 |      100 |     100 |     100 |                   
  grant-mint-and-burn-roles.ts         |     100 |      100 |     100 |     100 |                   
  grant-mint-role.ts                   |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  is-burner.ts                         |     100 |      100 |     100 |     100 |                   
  is-minter.ts                         |     100 |      100 |     100 |     100 |                   
  mint.ts                              |     100 |     90.9 |     100 |     100 | 85                
  revoke-burn-role.ts                  |     100 |      100 |     100 |     100 |                   
  revoke-mint-role.ts                  |     100 |      100 |     100 |     100 |                   
  set-ccip-admin.ts                    |     100 |      100 |     100 |     100 |                   
  transfer-token-ownership.ts          |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/solana               |   99.71 |    97.52 |   98.13 |   99.71 |                   
  index.ts                             |   99.66 |      100 |   97.22 |   99.66 | 253-254,2375-2380 
  operation.ts                         |     100 |      100 |     100 |     100 |                   
  query.ts                             |     100 |      100 |     100 |     100 |                   
  serialize.ts                         |     100 |     92.3 |     100 |     100 | 27                
  submit.ts                            |   99.23 |     87.5 |     100 |   99.23 | 123               
  validate.ts                          |     100 |    99.32 |     100 |     100 | 433               
 ccip-sdk/src/cct/solana/programs      |     100 |      100 |     100 |     100 |                   
  alt.ts                               |     100 |      100 |     100 |     100 |                   
  fee-quoter.ts                        |     100 |      100 |     100 |     100 |                   
  router.ts                            |     100 |      100 |     100 |     100 |                   
  token-pool.ts                        |     100 |      100 |     100 |     100 |                   
  token.ts                             |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/cct/solana/token         |     100 |      100 |     100 |     100 |                   
  constants.ts                         |     100 |      100 |     100 |     100 |                   
 ...rc/cct/solana/token-admin-registry |     100 |      100 |     100 |     100 |                   
  constants.ts                         |     100 |      100 |     100 |     100 |                   
 ...na/token-admin-registry/operations |   99.63 |    98.76 |     100 |   99.63 |                   
  accept-admin.ts                      |     100 |      100 |     100 |     100 |                   
  append-to-lookup-table.ts            |     100 |      100 |     100 |     100 |                   
  create-lookup-table.ts               |     100 |      100 |     100 |     100 |                   
  get-supported-tokens.ts              |     100 |      100 |     100 |     100 |                   
  get-token-admin-registry.ts          |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  ...override-pending-administrator.ts |     100 |      100 |     100 |     100 |                   
  register-admin.ts                    |   98.03 |       95 |     100 |   98.03 | 219-223           
  set-pool.ts                          |     100 |      100 |     100 |     100 |                   
  transfer-admin.ts                    |     100 |      100 |     100 |     100 |                   
 ...c/cct/solana/token-pool/operations |   99.64 |    98.44 |     100 |   99.64 |                   
  accept-pool-ownership.ts             |     100 |      100 |     100 |     100 |                   
  append-remote-pool-addresses.ts      |     100 |      100 |     100 |     100 |                   
  apply-chain-updates.ts               |     100 |    98.27 |     100 |     100 | 158               
  configure-allowlist.ts               |     100 |      100 |     100 |     100 |                   
  create-token-multisig.ts             |    95.9 |     92.5 |     100 |    95.9 | ...01-102,104-109 
  delete-chain-remote-config.ts        |     100 |      100 |     100 |     100 |                   
  deploy-token-pool.ts                 |     100 |      100 |     100 |     100 |                   
  edit-chain-remote-config.ts          |     100 |      100 |     100 |     100 |                   
  get-token-pool-remotes.ts            |     100 |      100 |     100 |     100 |                   
  get-token-pool-state.ts              |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  init-chain-remote-config.ts          |     100 |      100 |     100 |     100 |                   
  provide-liquidity.ts                 |     100 |      100 |     100 |     100 |                   
  remove-from-allowlist.ts             |     100 |      100 |     100 |     100 |                   
  set-can-accept-liquidity.ts          |     100 |      100 |     100 |     100 |                   
  set-chain-rate-limit.ts              |   99.15 |    96.15 |     100 |   99.15 | 65-66             
  set-rate-limit-admin.ts              |     100 |      100 |     100 |     100 |                   
  set-rebalancer.ts                    |     100 |      100 |     100 |     100 |                   
  transfer-pool-ownership.ts           |     100 |      100 |     100 |     100 |                   
  withdraw-liquidity.ts                |     100 |      100 |     100 |     100 |                   
 ...dk/src/cct/solana/token/operations |     100 |    97.98 |     100 |     100 |                   
  approve-token.ts                     |     100 |      100 |     100 |     100 |                   
  create-token-account.ts              |     100 |      100 |     100 |     100 |                   
  deploy-token.ts                      |     100 |      100 |     100 |     100 |                   
  get-token-info.ts                    |     100 |       70 |     100 |     100 | 69,80-81          
  index.ts                             |     100 |      100 |     100 |     100 |                   
  mint-tokens.ts                       |     100 |      100 |     100 |     100 |                   
  set-token-authority.ts               |     100 |    97.61 |     100 |     100 | 141               
  update-metadata-authority.ts         |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/errors                   |   91.37 |    78.61 |   63.63 |   91.37 |                   
  CCIPError.ts                         |     100 |      100 |     100 |     100 |                   
  codes.ts                             |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  pure.ts                              |     100 |       75 |     100 |     100 | 32                
  recovery.ts                          |     100 |      100 |     100 |     100 |                   
  specialized.ts                       |   89.48 |    76.19 |   61.76 |   89.48 | ...3926,3949-3958 
  utils.ts                             |   94.44 |    81.48 |     100 |   94.44 | 15,17,22,24       
 ccip-sdk/src/evm                      |   93.48 |    83.37 |   92.85 |   93.48 |                   
  const.ts                             |   98.66 |    92.85 |     100 |   98.66 | 122-123           
  errors.ts                            |   91.98 |     82.3 |     100 |   91.98 | ...85,239-242,247 
  exec-fixtures.test.helpers.ts        |   88.39 |       75 |      80 |   88.39 | ...01-105,107-111 
  extra-args.ts                        |   98.07 |    63.93 |     100 |   98.07 | ...85-186,211-212 
  fork.test.data.ts                    |     100 |      100 |     100 |     100 |                   
  gas.ts                               |   98.19 |    63.15 |     100 |   98.19 | 90-91,93          
  hasher.ts                            |     100 |     92.3 |     100 |     100 | 135               
  index.ts                             |   89.37 |       82 |   91.35 |   89.37 | ...2894,3051-3082 
  logs.ts                              |   99.16 |     92.3 |      90 |   99.16 | 70-71,76-77       
  messageCodec.ts                      |     100 |      100 |     100 |     100 |                   
  messages.ts                          |     100 |      100 |     100 |     100 |                   
  offchain.ts                          |    87.5 |    71.42 |     100 |    87.5 | 13-14             
  simulate.ts                          |     100 |    94.82 |     100 |     100 | 109-111,425       
  types.ts                             |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/evm/viem                 |   79.76 |    90.62 |   69.23 |   79.76 |                   
  client-adapter.ts                    |     100 |       90 |     100 |     100 | 48,74             
  index.ts                             |     100 |      100 |     100 |     100 |                   
  wallet-adapter.ts                    |   63.09 |     90.9 |   55.55 |   63.09 | ...91-124,131-157 
 ccip-sdk/src/hasher                   |   94.24 |    80.35 |     100 |   94.24 |                   
  common.ts                            |     100 |      100 |     100 |     100 |                   
  hasher.ts                            |     100 |      100 |     100 |     100 |                   
  index.ts                             |     100 |      100 |     100 |     100 |                   
  merklemulti.ts                       |   93.43 |       78 |     100 |   93.43 | ...06-307,315-316 
 ccip-sdk/src/shared                   |   85.32 |     86.9 |   82.35 |   85.32 |                   
  bcs-codecs.ts                        |   79.07 |    65.21 |   66.66 |   79.07 | ...42-252,260-269 
  codec.ts                             |    94.3 |       95 |     100 |    94.3 | 139-140,178-186   
  constants.ts                         |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/solana                   |   90.09 |    83.23 |   93.68 |   90.09 |                   
  cleanup.ts                           |   58.17 |     62.5 |      80 |   58.17 | ...28-247,259-263 
  coder.ts                             |     100 |    88.88 |     100 |     100 | 33-36             
  exec-v2.ts                           |   97.67 |    87.71 |     100 |   97.67 | ...69-371,469-470 
  exec.ts                              |   81.59 |    63.33 |   83.33 |   81.59 | ...76-480,520-521 
  extra-args.ts                        |   79.51 |       84 |   83.33 |   79.51 | 137-195           
  fork.test.data.ts                    |     100 |      100 |     100 |     100 |                   
  gas.ts                               |   92.06 |       75 |     100 |   92.06 | ...,81-90,170-171 
  hasher.ts                            |   96.49 |    81.81 |     100 |   96.49 | 64-67             
  index.ts                             |   89.62 |     82.5 |   93.22 |   89.62 | ...2317,2321-2354 
  logs.ts                              |   90.11 |     80.7 |     100 |   90.11 | ...50-151,163-164 
  offchain.ts                          |     100 |      100 |     100 |     100 |                   
  resolution.ts                        |   99.82 |    98.38 |     100 |   99.82 | 199               
  send-v2.ts                           |   97.52 |    96.22 |     100 |   97.52 | 177-182,282-283   
  send.ts                              |   96.36 |    67.85 |     100 |   96.36 | ...07,412-413,447 
  signatures-cache.ts                  |   79.78 |    71.15 |    87.5 |   79.78 | ...51-260,274-275 
  token-admin-registry.ts              |     100 |    96.96 |     100 |     100 | 60                
  token-pool.ts                        |     100 |      100 |     100 |     100 |                   
  types.ts                             |     100 |      100 |     100 |     100 |                   
  utils.ts                             |   86.22 |    83.59 |   86.66 |   86.22 | ...71-772,973-976 
  v1.ts                                |   96.63 |       86 |     100 |   96.63 | 66-69,122-125     
 ccip-sdk/src/sui                      |   81.82 |    70.63 |   88.62 |   81.82 |                   
  discovery.ts                         |   47.43 |    47.36 |      60 |   47.43 | ...35-783,786-820 
  events.ts                            |   89.58 |    67.46 |     100 |   89.58 | ...20-627,686-699 
  exec.ts                              |   30.71 |      100 |       0 |   30.71 | 37-89,101-153     
  execution.test.data.ts               |     100 |      100 |     100 |     100 |                   
  grpc-shapes.ts                       |   91.87 |    67.51 |     100 |   91.87 | ...1026,1172-1175 
  grpc.ts                              |    91.4 |    79.62 |   91.83 |    91.4 | ...1056-1057,1081 
  hasher.ts                            |   98.19 |    66.66 |     100 |   98.19 | 35,51             
  index.ts                             |   77.68 |    70.75 |    85.5 |   77.68 | ...2379,2395-2396 
  logs.ts                              |   97.28 |    66.66 |     100 |   97.28 | ...62-165,186-187 
  objects.ts                           |   53.82 |    84.48 |   83.33 |   53.82 | ...60-316,327-470 
  types.ts                             |     100 |      100 |     100 |     100 |                   
 ccip-sdk/src/sui/manuallyExec         |   53.36 |       75 |      50 |   53.36 |                   
  encoder.ts                           |    83.9 |    66.66 |     100 |    83.9 | 51-58,73-77,82    
  index.ts                             |   33.82 |      100 |       0 |   33.82 | 47-136            
 ccip-sdk/src/ton                      |   91.75 |    84.02 |   92.42 |   91.75 |                   
  exec.ts                              |     100 |      100 |     100 |     100 |                   
  extra-args.ts                        |   98.66 |    72.72 |     100 |   98.66 | 156-157,222       
  hasher.ts                            |   78.07 |    77.77 |      75 |   78.07 | 100-108,156-187   
  index.ts                             |   93.09 |     86.1 |   85.93 |   93.09 | ...2207,2214-2215 
  logs.ts                              |   94.78 |    86.88 |     100 |   94.78 | ...17-624,680-683 
  send.ts                              |   95.52 |    66.66 |     100 |   95.52 | 37-44,188         
  ton-cache.ts                         |     100 |    96.55 |     100 |     100 | 102               
  types.ts                             |   91.24 |    81.25 |     100 |   91.24 | ...61-63,71-74,92 
  utils.ts                             |    77.4 |    70.58 |     100 |    77.4 | ...52-410,412-415 
 ccip-sdk/src/verifiers                |   98.13 |       91 |     100 |   98.13 |                   
  codec.ts                             |   96.87 |    89.13 |     100 |   96.87 | 51-53,70,97       
  index.ts                             |     100 |      100 |     100 |     100 |                   
  transport.ts                         |   98.54 |     87.5 |     100 |   98.54 | 84-85             
 scripts                               |   90.38 |       73 |     100 |   90.38 |                   
  test-endpoints.ts                    |   98.58 |       90 |     100 |   98.58 | 165-167,279       
  useResource.ts                       |   83.57 |    61.66 |     100 |   83.57 | ...81-286,301-302 
---------------------------------------|---------|----------|---------|---------|-------------------

@andrevmatos andrevmatos left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address the two inline comments to minimize public interface changes and keep decimals resolution automatic.

Comment thread ccip-sdk/src/chain.ts Outdated
* @param tokenPool - Token pool address on this chain
* @returns The decimals the pool declares for its token
*/
getTokenPoolDecimals?(tokenPool: string): Promise<number>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please expose the pool’s decimals as an optional decimals property from getTokenPoolConfig, instead of adding Chain.getTokenPoolDecimals. Decimals belong to the pool configuration. Keep the lookup and fallback logic internal, and update the callers to use the existing API. Pools without getTokenDecimals() should remain readable.

* pools read, so destination preflights don't need the on-chain view either.
**/
export async function parseTokenAmounts(source: Chain, transferTokens: readonly string[]) {
export async function parseTokenAmounts(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please keep --transfer-tokens as token=amount and remove the new caller-supplied tokenAmounts[].extraData and destDecimals fields. Resolve decimals internally from the token, then its pool. For preflight conversions, use the chain family’s static decimals value as the final fallback. Keep pool-generated extraData automatic. Apply this to SDK callers too: getDestTokenAmount still reads source-token metadata directly when extraData is absent. Add tests for both sides and update the docs and recovery hints.

@SyedAsadKazmi SyedAsadKazmi changed the title feat(sdk): support tokens without the optional ERC-20 decimals() view via pool-declared and explicit decimals feat(sdk): support tokens without the optional ERC-20 decimals() view via pool-declared and family-default decimals Oct 22, 2026

@andrevmatos andrevmatos left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two follow-up requests on source amount parsing and RPC error handling.

Comment thread ccip-cli/src/commands/utils.ts Outdated
Comment on lines +754 to +760
const decimals = await resolveTokenDecimals(source, token, async () => {
if (!router) return undefined
const registry = await source.getTokenAdminRegistryFor(router).catch(() => undefined)
if (!registry) return undefined
return (await source.getRegistryTokenConfig(registry, token)).tokenPool
})
return { token, amount: parseUnits(amount_, decimals) }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P1] Keep family defaults out of source transfer amount parsing

Please require token- or pool-declared decimals before parseUnits; family defaults should apply only to preflights. I reproduced token=0.001 resolving to 1000n with a six-decimal pool, but 1000000000000000n after a registry timeout, because the resolver suppresses the error and falls back to 18. This changes the actual transfer amount by 10^12. Please propagate lookup failures here and add a regression test for this case.

Comment thread ccip-sdk/src/evm/index.ts
try {
decimals = await contract.decimals()
} catch (err) {
throw new CCIPTokenDecimalsUnavailableError(token, {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Preserve RPC failures instead of reporting missing decimals

This catch also converts RPC failures into CCIPTokenDecimalsUnavailableError. I reproduced a TIMEOUT becoming TOKEN_DECIMALS_UNAVAILABLE with isTransient: false. Please emit this typed error only for recognized unavailable-method or unusable-return cases, and preserve transport errors for retry or simulation-unavailable handling. Also avoid suppressing transport failures in the lazy pool resolver (resolveTokenDecimals), where they currently trigger the family-default fallback. Please add timeout regression tests for both paths.

@andrevmatos andrevmatos left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One further request on destination pool selection.

Comment thread ccip-sdk/src/gas.ts Outdated
.getTokenPoolRemotes(sourcePoolAddress, dest.network.chainSelector)
.catch(() => undefined)
const pools = remotes?.[dest.network.name]?.remotePools
if (pools?.length) return pools[pools.length - 1]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Use the registered destination pool for decimals resolution

Please resolve the pool through the destination TokenAdminRegistry when offRamp is available, as checkExecute does. Selecting the last source-configured remote pool does not ensure it matches the registered destination pool. I reproduced conversion using six decimals from the last remote pool while the registered pool declares eighteen; the registry is never queried. This makes conversion and execution use different decimals. Using the destination registry also removes the repeated source remote lookup and ordering assumption. Please add a regression test where the registered pool differs from the last remote pool.

@andrevmatos andrevmatos left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Documentation corrections for recovery guidance and pool-generated message data.

explicitly
```

`decimals()` is an **optional** view in ERC-20 — some tokens don't implement it. The CLI resolves the decimals automatically from the token pool's `getTokenDecimals()` (pool v1.5.1+); preflights additionally fall back to the chain family's default. For the transfer amount itself nothing is guessed — this error means neither the token nor its pool could declare them (e.g. a v1.5.0 pool). To declare them yourself, pass `tokenAmounts[].extraData` with `abi.encode(['uint256'], [decimals])` (the source-decimals declaration CCIP pools read).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please remove the advice to supply tokenAmounts[].extraData as a decimals override. The CLI has no such option, and SDK send inputs (MessageInput.tokenAmounts) now accept only { token, amount }. Emitted messages and preflight inputs can carry pool data, but that is not a supported override for source amount parsing. Document automatic token/pool resolution and failure when neither declares decimals. Please align the SDK querying-data page, error reference, and recovery hints too.

Comment thread ccip-api-ref/docs-cli/send.mdx Outdated

`decimals()` is an **optional** view in ERC-20 — some tokens don't implement it. When the token doesn't, the CLI resolves its decimals automatically from the token pool's `getTokenDecimals()` (pool v1.5.1+) — the same value the pool itself uses for its conversion. A plain `token=amount` just works; no decimals input is needed. If neither the token nor its pool can declare them, the send fails with `TOKEN_DECIMALS_UNAVAILABLE` rather than guessing — these decimals determine the actual transfer amount.

The source pool also declares its decimals in the message's `extraData` (the `destPoolData` it returns from `lockOrBurn`), so destination preflights never need the token's on-chain view either. The on-chain message itself ignores it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please correct the claim that the on-chain message ignores this data. Pool-generated destPoolData travels in the emitted message and reaches destination releaseOrMint as sourcePoolData; the destination pool uses it for decimals conversion. It is protocol data, not SDK-only metadata. Also qualify the claim that preflights never need the token view: extraData can declare source decimals, but preflights still resolve destination decimals.

andrevmatos
andrevmatos previously approved these changes Oct 22, 2026
@andrevmatos
andrevmatos merged commit 676afcf into main Oct 23, 2026
17 of 21 checks passed
@andrevmatos
andrevmatos deleted the feat/token-decimals-fallbacks branch October 23, 2026 18:32
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.

2 participants