Skip to content

docs(examples): token-lab — TRC20 and TRC10 on a private chain - #217

Merged
kuny0707 merged 1 commit into
tronprotocol:developfrom
barbatos2011:docs/token-lab
Aug 6, 2026
Merged

docs(examples): token-lab — TRC20 and TRC10 on a private chain#217
kuny0707 merged 1 commit into
tronprotocol:developfrom
barbatos2011:docs/token-lab

Conversation

@barbatos2011

Copy link
Copy Markdown

Two recipes that create a private chain, mint a token, drive transfers through it with txgen, and assert the receivers hold exactly what was sent.

$ trond recipe run --file examples/token-lab/trc20.yaml --allow-host-exec \
    --param lab_dir=examples/token-lab --param sender_key=$SR_PRIVATE_KEY
recipe trc20-lab: status=success, 5 steps, 16214ms

$ trond recipe run --file examples/token-lab/trc10.yaml --allow-host-exec ...
recipe trc10-lab: status=success, 5 steps, 6793ms

These are the first real consumers of recipe run --file (#213) and kind: host (#214) — and writing them is what surfaced the two substitution bugs fixed in #216.

What they actually carry

Not the token contract. Four chain parameters that nothing else in this repo documents, each of which makes a whole feature silently unusable:

parameter without it
vm.supportConstant read-only contract calls refused
committee.allowTvmConstantinople
committee.allowTvmSolidity059
committee.allowTvmIstanbul
deploy returns contractRet: SUCCESS, then every call returns empty with no energy used
committee.allowSameTokenName transferasset wants the token name, so every tool sending the numeric id gets No asset! — as though nothing was issued

The shipped private template already sets allowCreationOfContracts = 1, which is what makes the TVM case so confusing: deployment works, execution does not. It reads as a broken contract rather than a chain missing its upgrades.

All of these seed the dynamic property store at genesis, so setting them on a running chain does nothing — the chain has to be recreated. Between them they cost about two hours to find. The README says so, with the getchainparameters query to check rather than reason.

Choices

  • Compiled artifacts are committed, so no solc is needed. The source is here too, with a note that recompiling needs evmVersion istanbul — solc 0.8.20+ emits PUSH0, which java-tron's TVM does not implement.
  • The expected total is computed (tx_count × amount) rather than a literal. My first version hardcoded 200000, which silently stops matching the moment someone changes tx_count.
  • Not wired into CI. It needs Docker and node, e2e already runs two minutes, and a flaky example is worse than none.

How the two differ

Exactly two steps — mint and verify — because a TRC20 balance sits behind a contract call while a TRC10 balance sits on the account in assetV2. Adding a third token type is those two steps and nothing else.

Two encoding traps are documented for anyone writing their own scripts: getaccount returns asset_issued_name hex-encoded but asset_issued_ID as a plain decimal string — hex-decoding the id yields bytes that still look like a value ("1000001"0x10 0x00 0x00), so the mistake survives as plausible data instead of erroring. I made exactly that mistake.

Verification

Both recipes were run from their committed paths immediately before this commit, not from the scratch directory they were developed in. That caught two things a copy would have hidden: a template still referencing its old filename, and a cleanup glob that had deleted both .tmpl.json files.

make test -race — 25 packages, 0 failures.

Two recipes that create a private chain, mint a token, drive transfers
through it with txgen, and assert the receivers hold exactly what was
sent. Roughly 7-16s each once the image is pulled.

They are the first real consumers of `recipe run --file` and `kind: host`,
and they exist mostly to carry four chain parameters that nothing else in
this repo documents:

  vm.supportConstant              read-only contract calls are refused
  committee.allowTvmConstantinople
  committee.allowTvmSolidity059
  committee.allowTvmIstanbul      the deploy returns contractRet: SUCCESS,
                                  and then every call returns empty with no
                                  energy used
  committee.allowSameTokenName    transferasset wants the token NAME, so
                                  every tool sending the numeric id gets
                                  "No asset!" as though nothing was issued

The shipped private template already sets allowCreationOfContracts = 1,
which is exactly what makes the TVM case confusing: deployment works,
execution does not, and it reads as a broken contract rather than a chain
missing its upgrades. All of these seed the dynamic property store at
genesis, so setting them on a running chain does nothing — the chain has
to be recreated. Between them they cost about two hours to find; the
README says so, with the getchainparameters query to check rather than
reason.

Compiled artifacts are committed so no solc is needed to run this. The
source is here too, with a note that recompiling needs evmVersion
istanbul: solc 0.8.20+ emits PUSH0, which java-tron's TVM does not
implement.

The two recipes differ in exactly two steps — mint and verify — because a
TRC20 balance sits behind a contract call while a TRC10 balance sits on
the account in assetV2. Adding a third token type is those two steps and
nothing else.

Not wired into CI: it needs Docker and node, e2e already runs two minutes,
and a flaky example is worse than none. Both recipes were run from their
committed paths immediately before this commit.
@kuny0707
kuny0707 merged commit 8d5d9d6 into tronprotocol:develop Aug 6, 2026
10 checks passed
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