hashgraph / hashgraph/asset-tokenization-studio
docs: state that the transferFrom operator is never KYC-checked (only from/to are), so market and escrow contracts must not be granted KYC
- Dominant language
- TypeScript
- Stars
- 33
- Forks
- 28
- Avg merge
- 15h 36m
- Merged PRs (30d)
- 8
Description
## Summary
Every order-book, escrow or settlement contract built on ATS moves tokens with `transferFrom` and has to answer one question first: does the operator itself need KYC? The contracts answer "no", but the documentation does not say so, and the safe-looking guess ("grant KYC to the market contract as well") silently turns the market into an eligible token holder.
## What the code does (tag `v.8.0.0-ats`, commit be4f860e408ec5b1a24d12feb6f872aabff69319)
`packages/ats/contracts/contracts/domain/asset/ERC1594StorageWrapper.sol`, `isAbleToTransferFromByPartition(from, to, partition, value, ...)` (the function behind `canTransferFrom`), in order:
1. `_genericChecks()` — clearing / pause state.
2. zero-address check on `from` and `to`.
3. `_isCompliant(from, to, value, sender, checkSender)` with `checkSender = from != sender && !hasRole(protectedPartitionsRole(partition), sender)`. When `checkSender` is true the **operator** is run through `_validateAccountForTransfer` (recovered-wallet check and control list) and `_validateSenderCompliance` (the external compliance contract); then `from` and `to` go through the control list and the compliance contract.
4. `_isIdentified(from, to)` — KYC / identity registry for **`from` and `to` only**. The operator is not passed in.
5. allowance (`checkAllowance = checkSender && !isAuthorized(partition, sender, from)`), partition, balance.
So an operator moving someone else's tokens needs an allowance (or the protected-partition role) and must not be blocked by the control list, but is never required to hold KYC.
Verified live: Bond Desk's `BondMarket` (https://github.com/AbhimanyuAjudiya/bond-desk) fills orders with `transferFrom` on a bond issued through the testnet factory `0.0.9213391` with `internalKycActivated: true`. The market holds no KYC and every fill passes the token's own `canTransferFrom`; the fork test `contracts/test/fork/AtsFork.t.sol::test_fork_marketNotKycd_stillPassesOperatorCheck` pins this against testnet state.
## What the docs say
- `docs/ats/user-guides/token-operations.md`, line 54: "Both sender and receiver must have valid KYC"; line 75: "Source and destination accounts must pass all compliance checks (KYC, control lists, etc.)".
- Nothing, anywhere in `docs/` or the SDK README, about what applies to the operator / spender in `transferFrom` and `operatorTransferByPartition`.
"Sender" in the first sentence reads as `msg.sender` to an integrator writing a contract, which is exactly the wrong conclusion here.
## Suggested fix
A short "who is checked" table in the compliance guide (and one line under `transferFrom` in the SDK README):
| Party | Control list + compliance contract | KYC / identity | Allowance |
| --- | --- | --- | --- |
| `from` | yes | yes | — |
| `to` | yes | yes | — |
| operator (`msg.sender != from`, no protected-partition role) | yes | **no** | yes |
plus the one sentence integrators are looking for: an operator contract does not need, and should not be given, KYC.
Contributor guide
Research direction
Start with docs/ats/user-guides/token-operations.md, especially lines 54 and 75, then inspect packages/ats/contracts/contracts/domain/asset/ERC1594StorageWrapper.sol and the SDK README. Document which parties are checked for transferFrom and operatorTransferByPartition, including the operator's KYC exception, and verify the new wording is consistent with the cited function behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- solidity, typescript
- Domain
- blockchain, documentation
- Issue type
- Documentation
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100