hashgraph / hashgraph/asset-tokenization-studio
Offering back: discovery-based Sourcify verification for a full ATS deployment (121/121 exact_match), and notes from deploying 8.0.0 without Hardhat
- Dominant language
- TypeScript
- Stars
- 33
- Forks
- 28
- Avg merge
- 15h 36m
- Merged PRs (30d)
- 8
Description
We built a secondary market on ATS ([tenor](https://github.com/dadadave80/tenor)), deploying a fresh
system to Hedera testnet from `@hashgraph/asset-tokenization-contracts@8.0.0`. Two things came out of
it that belong upstream.
## 1. Sourcify verification of a whole ATS deployment
[`scripts/verify-ats.ts`](https://github.com/dadadave80/tenor/blob/main/scripts/verify-ats.ts) got
**all 121 contracts** to `exact_match`. It is discovery-based, not a hand-maintained address list:
- Start from the deployment record (resolver proxy, ProxyAdmin, factory proxy, token), read the
resolver's ERC-1967 slots, then enumerate every facet via `getBusinessLogicKeys` +
`resolveLatestBusinessLogic`.
- Find linked libraries in their callers' runtime at each artifact's `deployedLinkReferences`
offsets, repeating until nothing new appears.
- Identify each address by its runtime, metadata hash included, against every artifact the package
ships, masking only link references and a library's call-protection address. An address nothing
matches is reported, not submitted.
- Rebuild the standard JSON per contract, submit to `POST /v2/verify/296/{address}`, poll each job.
Anything already `exact_match` is skipped, so re-runs are idempotent. `--dry-run` builds every
input and submits nothing.
**What would make this unnecessary:** the package's `files` excludes `artifacts/build-info/`, so the
standard JSON has to be reconstructed. We recovered the settings from upstream's `hardhat.config.ts`
— solc `0.8.28+commit.7893614a`, optimizer at **100 runs**, `evmVersion: cancun`, and no `libraries`
entry (Hardhat links after compiling; adding one moves the metadata hash) — and pinned the Solidity
dependencies at the versions upstream's lockfile pins (OZ and OZ-upgradeable 4.9.6, t-rex 4.1.6,
onchain-id 2.2.1) from npm tarballs against registry integrity hashes, since OZ is only a
devDependency here. Shipping `build-info` or the standard JSON inputs would remove that guesswork for
every downstream deployer.
Happy to open a PR if it is wanted. Where should it live — a script here, a documented recipe, or
something you would rather own?
## 2. Deploying 8.0.0 without Hardhat
The package already ships its deploy tooling compiled under `build/scripts/cli/`
(`deploySystemWithNewBlr.js`, `deploySystemWithExistingBlr.js`), with runtime dependencies of only
`ethers ^6`, `zod`, `dotenv`, `tslib`, `@onchain-id/solidity` — no Hardhat, no peers.
`infrastructure/signer.js` builds a plain `ethers.Wallet`/`JsonRpcProvider`, and `hedera-testnet` is a
first-class `KNOWN_NETWORKS` entry. We deployed the full system with Bun + ethers out of
`node_modules`: no clone, no Hardhat install. No compiler settings had to be matched to deploy —
0.8.28 / 100 runs / cancun mattered only for verification.
Two doc notes. The README's "Deployment & Tasks" section defers to `[Scripts README](scripts/README.md)`
for everything, but the published package ships no `scripts/` directory — that link is dead for a
consumer. Its quick-start commands are `npm run deploy:hardhat -- --network hedera-testnet` and
`npm run deploy`, repo scripts a consumer cannot run, and `build/scripts/cli/` is never mentioned.
Second, the env names are prefixed and indexed (`HEDERA_TESTNET_JSON_RPC_ENDPOINT`,
`_MIRROR_NODE_ENDPOINT`, `_PRIVATE_KEY_0`), parsed at module load, before a consumer's own code runs.
## 3. Three smaller things
- The test ISIN constant `US0000000000` fails `isinValidator`'s on-chain ISO 6166 check digit, so it
is not a usable example for anyone copying it.
- `grantKyc`'s last argument is the KYC issuer, checked against the token's SSI issuer registry, not a
role: an address holding `ROLE_KYC`, `ROLE_KYC_MANAGER` and `ROLE_INTERNAL_KYC_MANAGER` still
reverts `AccountIsNotIssuer` until `addIssuer` is called under `ROLE_SSI_MANAGER` — the one
non-obvious step between "the token exists" and "anyone can be verified".
- `InvalidKycStatus()` covers both re-granting an already-granted account and a transfer to an
unverified holder, so a retry after a partial failure fails pointing at the opposite problem.
Contributor guide
Research direction
Start by reading the README's Deployment & Tasks section, scripts/README.md, and the packaged build/scripts/cli/ deployment entry points. Review the linked scripts/verify-ats.ts for the discovery and Sourcify workflow, then confirm with maintainers whether the upstream work should be a script, documentation, or both. Done means the chosen consumer path is reproducible and the deployment, verification, environment, ISIN, issuer, and KYC behavior are documented accurately.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bun, node.js, typescript
- Domain
- blockchain, devops, documentation, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100