Skip to content

Build1 publisher2 min readPublished

ERC-3643 code at version 4.1.3 checks compliance on mints the standard exempts

Pharos Production found ERC-3643's pinned token calls canTransfer inside mint, though the standard says minting bypasses compliance. Under that code, a mint to a wallet the compliance modules reject can revert, so issuers working from the written text have two behaviors to reconcile first.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying ERC-3643 code at version 4.1.3 checks compliance on mints the standard exempts
Generated illustration

What happened

  • The walkthrough pins the ERC-3643 repository at commit 2f0704dee9658ad9cd5b6ed82e7427da74c28345, which its package labels version 4.1.3.
  • It implements a recipient-country allowlist rule and runs 19 passing tests against real token, registry and compliance contracts, including a deliberately broken module and its regression.
  • In that version, transfer and transferFrom verify the recipient and run modular compliance; renewed sender eligibility has to be added and tested separately.
  • The pinned IdentityRegistry accepts any registered identity once the required claim-topic list is empty; the authors call that configuration behavior, not a vulnerability.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision Before anyone signs an issuance transaction, the release review has to settle which behavior its selected contracts follow: the standard's compliance bypass or the implementation's check.
  • exposure Without a retained mint-denial test, a dependency upgrade could change who may receive newly issued tokens with nobody deciding it; the walkthrough requires an explicit issuance-policy decision for any changed result.
  • constraint An onboarding check that only confirms each wallet has an identity contract does not establish that the wallet holds the credential a deployment requires.

Inside mint, the pinned Token contract calls `canTransfer(address(0), recipient, amount)` [2]. The zero address fills the sender slot; the recipient and amount are the real ones. The standard's transfer description puts minting in the same group as forced transfers, as paths that bypass compliance [1]. A runbook written from the standard would expect mint to skip the compliance modules. Only one of the two documents executes, and at this commit mint consults them [2].

The walkthrough's rule is a recipient rule. An ordinary transfer needs an eligible recipient whose registered country appears in an allowlist [18]. Those country values are registry records kept by authorized operators, and they do not reveal a wallet's physical location [14]. Wallet freezes, available balance and the pause state stay as separate token-level checks [15]. The mint-denial test captures what that recipient check does when it runs during issuance [7].

Pharos Production's broader argument is that an interface name does not settle behavior. An entry point can omit an ordinary permission check and still revert in a downstream module action [17]. "A statement that the token supports compliance cannot tell an integration engineer which call should revert," Pharos Production wrote [20]. Its deliverable, and in my view the right one for a permissioned token, is a table that ties each rule to a transaction and an assertion [21].

The passing tests describe one fixture [5]. Identity signatures in it are explicit test doubles, so the results establish transfer-control behavior inside that boundary [6]. The build uses Solidity 0.8.17, OpenZeppelin contracts and upgradeable contracts at 4.8.3, and the ONCHAINID package at 2.0.0 [4]. For the results to carry over, a deployment has to run the same commit and toolchain, and its real claim signatures have to behave the way the doubles do [1]. The authors describe the pin as "a reproducible source selection, not a recommendation to deploy an unreviewed repository head" [16].

The module is narrow by design. It restricts recipients [13]. It does not confiscate a holding when an investor's country changes, block every outbound movement or calculate ownership concentration, and the walkthrough treats each of those as a separate policy decision with its own enforcement point and tests [13]. On the identity side, registration ties a wallet to an identity and a country, while verification evaluates the required claim topics against the trusted issuer configuration [12]. The walkthrough says onboarding screens and operational runbooks should keep those two jobs distinct [12].

What to watch

  • Whether the ERC-3643 standard text is revised to match the canTransfer call in mint, or a later implementation drops that call.
  • Results from the same fixture run with real ONCHAINID claim signatures in place of the test doubles.
  • Whether deployed ERC-3643 identity registries are configured with an empty required-topic list.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories