What you will build.
An issuer plans fictional allocation DEMO-OFFER-01: 100 units remain and a purchaser requests 20. Test an ineligible purchaser, an allocation beyond supply and a paid purchase that has not been delivered. Nothing in this exercise constitutes an offering or investment recommendation.
Your working record
Create a private worksheet with columns for the source reference, observed state, responsible system, observation time, expected result and unresolved issue. Use the same fictional case throughout the steps; do not paste live personal or financial records into this exercise.
Run the example before changing it.
Inspect the baseline record below. Download and read the complete JavaScript file before running it. It uses only Node’s built-in test and assertion modules; there is no package installation, account connection or secret to configure.
{
"eligible": true,
"requested": 20,
"remaining": 100,
"paid": true,
"delivered": true
}Save it as nft-ico-token-offering.mjs. Open a terminal in that folder and run:
node --version
node --test nft-ico-token-offering.mjsExpected result: four passing tests and zero failures. These tests verify the teaching classifier only. They do not verify a production integration, security boundary or financial outcome.
File or test runner will not start?
Check that Node.js 22 or later is installed, the filename ends in .mjs rather than .mjs.txt, and your terminal is in the download folder. If a managed browser blocks scripts, open “Read the full exercise” and save that text locally under the same filename. Do not disable organizational security controls.
Read the full exercise
// Hybrid-Chain offline teaching model: nft-ico-token-offering
// Fictional fields/states; NOT an API client, authorization system or production implementation.
// No network calls, credentials, payments or file writes. Review before running.
// Requires Node.js 22+. Run: node --test nft-ico-token-offering.mjs
import test from 'node:test';
import assert from 'node:assert/strict';
export function inspect(record) {
if (!record.eligible) return 'PURCHASER_REVIEW_REQUIRED';
if (record.requested > record.remaining) return 'ALLOCATION_EXCEEDS_SUPPLY';
if (record.paid && !record.delivered) return 'PAID_DELIVERY_UNRESOLVED';
return 'ALLOCATION_READY_FOR_REVIEW';
}
const baseline = {
"eligible": true,
"requested": 20,
"remaining": 100,
"paid": true,
"delivered": true
};
const cases = [
{
"name": "reviewable allocation",
"patch": {},
"expected": "ALLOCATION_READY_FOR_REVIEW"
},
{
"name": "purchaser unresolved",
"patch": {
"eligible": false
},
"expected": "PURCHASER_REVIEW_REQUIRED"
},
{
"name": "excess allocation",
"patch": {
"requested": 101
},
"expected": "ALLOCATION_EXCEEDS_SUPPLY"
},
{
"name": "paid but undelivered",
"patch": {
"delivered": false
},
"expected": "PAID_DELIVERY_UNRESOLVED"
}
];
for (const example of cases) {
test(example.name, () => {
assert.equal(inspect({...baseline, ...example.patch}), example.expected);
});
}
Know what the tests demonstrate
- reviewable allocation
ALLOCATION_READY_FOR_REVIEW- purchaser unresolved
PURCHASER_REVIEW_REQUIRED- excess allocation
ALLOCATION_EXCEEDS_SUPPLY- paid but undelivered
PAID_DELIVERY_UNRESOLVED
Now change one fixture at a time. If you change a case’s input without changing its expected result, the test should fail. Read the actual-versus-expected difference and use the walkthrough to decide whether your rule or your expectation needs correcting. Keep an unchanged copy for comparison.
Work through the case, step by step.
- 01
Define the entitlement before the token
Do this
- Write DEMO-OFFER-01 and explain what a purchaser is intended to receive.
- Record the approved disclosure version, issuer and transfer conditions.
- Separate permission to publish information from permission to distribute the entitlement.
Expected resultThe allocation model has a defined subject and does not imply that a published listing authorizes an offering.
If your result is different
If the entitlement or required offering approvals are unresolved, stop before designing a real purchase flow.
- 02
Test purchaser and supply gates
Do this
- Run the baseline with eligible=true, requested=20 and remaining=100.
- Set eligible=false, then test requested=101 in a separate case.
- Confirm PURCHASER_REVIEW_REQUIRED and ALLOCATION_EXCEEDS_SUPPLY respectively.
Expected resultThe worksheet names two different reasons an allocation cannot proceed rather than reporting a generic checkout failure.
If your result is different
The numeric comparison is not a reservation engine. Production concurrent allocation requires an atomic supply-control mechanism.
- 03
Separate payment from delivery
Do this
- Set paid=true and delivered=false; expect PAID_DELIVERY_UNRESOLVED.
- Add separate provider-payment and asset-delivery references to the worksheet.
- Assign the unresolved delivery to an owner and define customer support/refund escalation outside the exercise.
Expected resultThe customer record can show money received without pretending the entitlement has been delivered.
If your result is different
Do not retry payment to resolve failed delivery. Reconcile the existing payment first.
- 04
Retain the disclosure trail
Do this
- Keep the disclosure reference used for the allocation, even if a newer version is published.
- Save the test cases and list additional checks for refunds, supply changes and transfer restrictions.
- Use the governance walkthrough to map which reviewed version a decision actually concerns.
Expected resultYou finish with a reviewable distribution design, not proof of investment quality, offering permission or exchange admission.
If your result is different
Any proposed external exchange listing remains a separate process; it is not a consequence of passing these local tests.
Review what you produced.
Save the worksheet, unmodified test output, one deliberately failing case and the explanation of its fix. A useful result includes an unresolved item with an owner; it is not just a screenshot of four green tests.
Map the model to actual systems.
The issuer owns commercial terms, legal classification, purchaser eligibility, disclosure accuracy, allocation, and unresolved delivery or refund handling.
For each worksheet field, name the owning system, exact current operation, permission and error behavior. Put “not available” next to any missing operation and assign a dependency owner. Do not substitute the teaching classifier for that missing integration.
Open the current API reference and inspect each operation’s request, response, scope and implementation status. Code examples on this page are local models only; they do not call those operations.
Take the next technical step.
Use your worksheet and failing-case notes in the next walkthrough. Keep the same reference trail so you can see which assumptions become actual observations—and which remain dependencies.
Review the approved disclosure decision