An ERC-20 / BEP-20 token built for the 42 School Tokenizer project, deployed and verified on the Ethereum Sepolia public test network.
| Token name | Avivien42 |
| Ticker | AVI42 |
| Decimals | 18 |
| Total supply | 1,000 AVI42 — fixed, minted once at deployment |
| Minting | none — the contract has no mint function |
| Standard | ERC-20, plus getOwner() so the same source is also BEP-20 conformant |
| Network | Ethereum Sepolia (chain id 11155111) |
| Contract address | 0xc03b51037d62FDD8196265Ce0c4911B4C45DA91b |
| Block explorer | Etherscan — source verified ✅ |
| Also verified on | Blockscout and Sourcify |
| Deployment tx | 0x94413a72…cf335ff1 |
.
├── README.md # this file — the choices made and why
├── code/ # the smart contract source
├── deployment/ # deployment script, the log of the actual deployment,
│ # and ops/ - one script per token operation
├── documentation/ # user guide + whitepaper
└── test/ # automated test suite (18 tests)
The subject leaves the chain free — it asks only that the standard of the chosen chain be respected, and names "ERC20 for ETH or BEP-20 for BSC" as its two examples. Both were viable here, and the contract is written so that it satisfies either.
Sepolia was chosen for three reasons:
- No real money, and reliably so. The subject forbids spending real funds, so the deployment has to run on a faucet-funded account. BNB Chain's testnet faucet now requires a minimum balance of real BNB on mainnet and was empty when this project was deployed; Sepolia's faucets dispense freely. A test network you cannot actually transact on is not a usable target — including on the day of the defense, when the token has to be demonstrated live.
- The reference EVM chain. Sepolia is Ethereum's own test network, maintained by the Ethereum foundation and used by most of the ecosystem. Solidity, Hardhat, OpenZeppelin, MetaMask and Etherscan are all built for it first.
- Three independent verifications. The source is published and matched against the deployed bytecode on Etherscan, Blockscout and Sourcify. Anyone can check the contract on the explorer of their choice rather than trusting a single one.
The same source also runs on BNB Smart Chain. BEP-20 is the ERC-20 interface with one
addition, getOwner(), which this contract implements — see
code/Avivien42.sol. hardhat.config.js keeps the BSC Testnet
network configured, so deploying there is the same command with a different --network
flag and no change to a single line of Solidity. That portability is the actual content
of the claim "BEP-20 is ERC-20", and it is the reason the choice of chain is a
deployment detail rather than a design decision.
Solidity is the language the EVM ecosystem is actually written in. Every audited library, every tutorial and every verification tool assumes it. Picking anything else (Vyper, Yul) would mean giving up OpenZeppelin and the explorers' Solidity verifiers for no benefit at this scale.
Hardhat was chosen over Truffle and Remix because:
- Truffle is discontinued (ConsenSys sunset it in 2023), so building on it means building on an unmaintained tool.
- Remix is a browser IDE. It is excellent for a quick experiment, but the project requires a git repository with reproducible, reviewable scripts. Remix does not give you a committed deployment script or a test suite.
- Hardhat gives an in-process EVM for fast tests, a scriptable deployment flow, and
hardhat-verify, which verified this contract on Etherscan, Blockscout and Sourcify with a single command.
Foundry would have been a reasonable alternative; Hardhat was preferred because the project's tooling (Node.js, npm) was already present and its JavaScript scripts are easier to read during a peer review than Solidity test contracts.
This is the single most important decision in the project.
Writing the ERC-20 interface from scratch is about 60 lines of code, and it is also where the overwhelming majority of historical token bugs live: wrong return values, missing events, unchecked arithmetic, broken allowance accounting. OpenZeppelin's implementation is audited, is used by a large share of tokens in production, and is what any reviewer already knows how to read.
Reusing a reviewed implementation and spending the saved effort on the parts that are
actually specific to this token (the supply policy, the privilege model) is the safer
engineering trade-off. The contract is still fully understood and documented — see
code/Avivien42.sol.
The subject says nothing at all about the supply — it only requires "42" in the name, which the token name already carries. Both numbers below are therefore project decisions and are defended as such.
Fixed rather than mintable. An owner-callable mint() would mean that every holder's
share can be diluted at any moment by a single address. The cap that usually accompanies
it only bounds the dilution; it does not remove it, and it still asks holders to trust
that the key behind that address is neither malicious nor stolen. Removing the function
removes the question: the supply written in the source is the supply that will exist
forever. That guarantee is verifiable by anybody reading the verified source on BscScan,
and it does not depend on anyone's good behaviour.
The cost of the decision is accepted knowingly: if more tokens are ever needed, there is no way to issue them — a new contract would have to be deployed. For a token whose supply policy is "there is no supply policy, it is a constant", that is the point rather than a limitation.
1,000 rather than millions. Large round supplies in this space are mostly theatre:
the number is chosen so that a single token looks cheap. This token has no price and no
market, so there is nothing to stage. 1,000 is a quantity a human can hold in their head,
and it makes the arithmetic during the defense readable — burn 42 tokens and totalSupply
visibly goes to 958.
Note that a small count costs no precision: with 18 decimals the smallest transferable unit is 10⁻¹⁸ of a token, so 1,000 tokens still divide into 10²¹ pieces.
The subject asks to think about "ownership and privileges". The conclusion reached here is that the safest set of privileges is the empty one:
| Decision | Reason |
|---|---|
| Fixed supply, minted once in the constructor | There is no mint function anywhere in the contract, so nobody — not the owner, not the deployer — can ever create another token. Holders do not have to trust a promise not to inflate their share: inflation is impossible by construction. |
| No privileged functions at all | The contract contains no onlyOwner entry point. There is no mint, no pause, no blacklist and no forced transfer. A stolen owner key gives an attacker no power whatsoever over the token. |
The owner role exists only as BEP-20 getOwner() |
BEP-20 extends ERC-20 with getOwner(), which identifies who issued the token. Being that on-chain label is the entire purpose of the role here. |
Ownable2Step instead of Ownable |
Handing the issuer label to a mistyped address would misattribute the token permanently. The two-step handover makes that impossible: the new owner has to accept the role from their own account. |
burn written directly, without ERC20Burnable |
The OpenZeppelin extension also ships burnFrom, which lets an approved spender destroy somebody else's tokens. This token has no integration that needs it, so only burn is exposed: the burner is always msg.sender, and destroying tokens you do not hold is not merely forbidden but impossible. |
| Owner passed to the constructor | Rather than hardcoding msg.sender, the initial owner is an explicit argument, so the deployer key and the owner role do not have to be the same account. |
| Secrets never committed | The private key lives in a git-ignored .env (or in Hardhat's encrypted keystore). Only .env.example is tracked. |
18 is the ERC-20/BEP-20 de-facto standard and what wallets, explorers and DEXs assume
by default. Deviating from it is a well-known source of integration bugs, so
decimals() is left at the OpenZeppelin default.
npm install # install dependencies
npx hardhat build # compile the contract
npx hardhat test # run the 18-test suiteDeploying and verifying:
cp .env.example .env # then fill in a throwaway private key and an Etherscan key
npx hardhat run deployment/deploy.js --network sepolia
npx hardhat verify --network sepolia <CONTRACT_ADDRESS> <OWNER_ADDRESS>Swap --network sepolia for --network bscTestnet to deploy the identical source to
BNB Smart Chain Testnet instead; both networks are configured in hardhat.config.js.
Full step-by-step instructions — including getting free test ETH, verifying the source
and adding the token to MetaMask — are in
documentation/README.md.
documentation/README.md— installation, deployment, verification and usage guide.documentation/whitepaper.md— what the token represents, its supply policy and its governance model.deployment/DEPLOYMENT_LOG.md— what was deployed, where, at what cost, and the post-deployment checks.documentation/defense-qa.md— question-and-answer sheet (in Russian) covering the blockchain concepts and every design decision made here.