Pass a List to a dApp#

A callable function can take a list as an argument, which lets one call handle many items: a batch of scores, a set of recipients, a basket of orders. This guide passes two lists, names and scores, and stores each pair.

Note

The script compiles on the public Testnet node (2026-10-25) with complexity 122. The TypeScript is typechecked against @decentralchain/transactions@5.0.1. It has not been broadcast as part of this documentation pass.

Before You Start#

You need Node.js 24 or later, the compileRide helper from Compile a Script, and two Testnet accounts with DCC from the faucet: one for the dApp, one to call it.

npm install @decentralchain/transactions@5.0.1

Write the Script#

Save this as ride/list-argument.ride:

{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}

# Records a score for each name in a single call: names[n] gets scores[n].
# Ride has no unbounded loops, so FOLD<10> caps a call at 10 pairs.

@Callable(i)
func setScores(names: List[String], scores: List[Int]) = {
  if (size(names) != size(scores)) then throw("names and scores must be the same length")
  else if (size(names) > 10) then throw("At most 10 scores per call")
  else {
    func addEntry(entries: List[IntegerEntry], name: String) =
      entries :+ IntegerEntry("score_" + name, scores[size(entries)])
    FOLD<10>(names, [], addEntry)
  }
}
  • List parameters are declared as List[String], List[Int], List[Boolean] or List[ByteVector]. A list argument can’t hold another list.

  • Ride has no open-ended loops. FOLD<N> (see Iterations with FOLD) walks a list of at most N items, so the script rejects longer lists before it folds. A larger N allows more items per call but raises the complexity.

  • size(entries) is the index of the current name, which is how addEntry finds the matching score.

Deploy the Script#

import { readFile } from 'node:fs/promises';
import { setScript, invokeScript, broadcast, waitForTx, libs, nodeInteraction } from '@decentralchain/transactions';
import { compileRide } from './compile-ride.js';

const nodeUrl = 'https://testnet-node.decentralchain.io';
const dAppSeed = 'dApp account secret seed phrase here';
const callerSeed = 'caller secret seed phrase here';
const dApp = libs.crypto.address(dAppSeed, '!');
const wait = (id: string) => waitForTx(id, { apiBase: nodeUrl, timeout: 120_000 });

// 1. Compile the script and set it on the dApp account
const source = await readFile(new URL('./ride/list-argument.ride', import.meta.url), 'utf8');
const deploy = setScript({ script: await compileRide(source, nodeUrl), chainId: '!' }, dAppSeed);
await broadcast(deploy, nodeUrl);
await wait(deploy.id);

Pass Lists#

A list argument is { type: 'list', value: [...] }, and every item in it is typed in turn:

// 2. Pass two lists: each argument is { type: 'list', value: [...] } of typed items
const tx = invokeScript(
  {
    dApp,
    call: {
      function: 'setScores',
      args: [
        {
          type: 'list',
          value: [
            { type: 'string', value: 'alice' },
            { type: 'string', value: 'bob' },
            { type: 'string', value: 'carol' },
          ],
        },
        {
          type: 'list',
          value: [
            { type: 'integer', value: 12 },
            { type: 'integer', value: 7 },
            { type: 'integer', value: 21 },
          ],
        },
      ],
    },
    chainId: '!',
  },
  callerSeed,
);
await broadcast(tx, nodeUrl);
await wait(tx.id);

const carol = await nodeInteraction.accountDataByKey('score_carol', dApp, nodeUrl);
console.log('score_carol:', carol?.value);

After the call, the dApp holds score_alice, score_bob and score_carol. If the lists have different lengths, or more than 10 items, the script throws and the call is rejected.