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]orList[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 mostNitems, so the script rejects longer lists before it folds. A largerNallows more items per call but raises the complexity.size(entries)is the index of the current name, which is howaddEntryfinds 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.