Where are the Veri SmartMetal contracts?
Veri SmartMetal contracts on Base
Veri SmartMetal is an ERC-1155 token at 0x4516a5D613C30A36D157d3b579813734cbb929a4 on Base, an ERC-1967 proxy in front of the Series1155V1 implementation, with a separate SeriesActivation contract that holds every token until its holder activates it; all three were deployed on 22 May 2025 and are built on QRToken.
Veri SmartMetal
- Chain#
- Base (eip155:8453)
- Implementation#
- Series1155V1 0x945D54B21a582d5D186Ae1E449DdC2a4Ce39E26c
- Deployed#
- Block 30,569,433 · 22 May 2025
- Source#
- Verified on BaseScan
- Transactions#
- All transactions
- Last verified#
- 13 Oct 2026
Series1155V1
- Chain#
- Base (eip155:8453)
- Deployed#
- Block 30,569,430 · 22 May 2025
- Source#
- Verified on BaseScan
- Transactions#
- All transactions
- Last verified#
- 13 Oct 2026
SeriesActivation
- Chain#
- Base (eip155:8453)
- Deployed#
- Block 30,569,436 · 22 May 2025
- First activation#
- Block 30,576,415 · 22 May 2025
- Source#
- Verified on BaseScan
- Transactions#
- All transactions
- Last verified#
- 13 Oct 2026
Three contracts make up Veri SmartMetal on Base (chain id 8453). The Fact sheets above list each one; this article says what each does, how they fit together and how to read them yourself. All three were deployed by the same account, 0x73196fa74d6061e02648078246a1fE4D93a7AC2f, within twelve seconds on 22 May 2025.
How the three fit together#
| Contract | Address | Role |
|---|---|---|
| Veri SmartMetal | 0x4516a5D613C30A36D157d3b579813734cbb929a4 | The token. An ERC-1967 proxy: the address wallets and explorers know, holding the balances and the series. |
Series1155V1 |
0x945D54B21a582d5D186Ae1E449DdC2a4Ce39E26c | The implementation the proxy delegates to: an ERC-1155 token with series, roles, royalties and pausing. |
SeriesActivation |
0x412E962bbAE0bB97CE98e74f3424543651a21ce3 | Holds every minted token until its holder activates it, then transfers it to the activator’s wallet. |
A SmartMetal token’s life runs through all three: the token contract mints it to SeriesActivation, SeriesActivation keeps it until someone proves they hold the key from its QR code, and the token then leaves for that person’s wallet. Activate a SmartMetal walks through that last step.
The token: an ERC-1967 proxy#
The address 0x4516a5D613C30A36D157d3b579813734cbb929a4 is an ERC1967Proxy of 129 bytes. It holds all the storage (balances, series, roles) and forwards every call to the implementation written in the EIP-1967 implementation slot. The proxy was created in block 30,569,433 on 22 May 2025 at 15:36:53 UTC (transaction). That one transaction:
- emitted
Upgraded(0x945D54B21a582d5D186Ae1E449DdC2a4Ce39E26c), the constructor setting the first implementation; - called
initialize(contractUri)through the proxy, which emittedInitialized(1); - granted the deployer five roles (see Roles).
The implementation slot still holds Series1155V1 at 0x945D54B21a582d5D186Ae1E449DdC2a4Ce39E26c (read on 13 Oct 2026; the command is under Check it yourself). The upgrade path is UUPS (UPGRADE_INTERFACE_VERSION() returns 5.0.0): upgradeToAndCall lives in the implementation, guarded by its _authorizeUpgrade, so the contract can be upgraded; the slot read on 13 Oct 2026 still names the original implementation.
Series1155V1#
Series1155V1 at 0x945D54B21a582d5D186Ae1E449DdC2a4Ce39E26c was deployed three blocks before the proxy, in block 30,569,430 (transaction). It is an exact match of its verified source, Solidity 0.8.28 with the optimizer on at 200 runs. It is part of QRToken, Patryk Dwórznik’s own framework, which Veri SmartMetal is built on, and was written by him. The QRToken reference documents the contract in full; this section covers what you meet when you read the Veri deployment.
On top of OpenZeppelin’s upgradeable ERC-1155 it adds:
- Series. A series is a group of tokens sharing one metadata folder on IPFS.
createSeries(cid, isFungible)registers one; its id iskeccak256of the CID string.listSeries,seriesCount,seriesTokenCount,seriesTokensandtokenSeriesread them. SmartMetal series lists the two that exist. - Minting by series.
mintBatch(to, seriesId, tokenIds, amounts)mints the given ids into a series; the caller chooses the ids. A non-fungible series only accepts an amount of 1 per id. - Metadata.
uri(id)returnsipfs://<series CID>/<id>.json. Series metadata can be updated or frozen in streamed steps (updateSeriesInitandupdateSeriesEmit,freezeSeriesInitandfreezeSeriesEmit); a frozen series emits aPermanentURIevent per token.contractURI()holds the contract-level metadata and can be frozen too. On 13 Oct 2026 nothing was frozen. - Roles, royalties and pausing. Access control by role (below), an ERC-2981 royalty that is unset (
royaltyInforeturns the zero address and 0), andpauseandunpause. It was not paused on 13 Oct 2026.
It reports support for the ERC-1155 (0xd9b67a26), ERC-1155 metadata URI (0x0e89341c) and ERC-2981 (0x2a55205a) interfaces.
Roles#
Role ids are keccak256 of the role name, except DEFAULT_ADMIN_ROLE, which is 0x00. The proxy’s creation transaction granted the deployer, 0x73196fa74d6061e02648078246a1fE4D93a7AC2f, these five, and hasRole still returned true for each on 13 Oct 2026:
| Role | Id | Lets its holder |
|---|---|---|
DEFAULT_ADMIN_ROLE |
0x00 |
grant and revoke the other roles |
MINTER_ROLE |
0x9f2d…56a6 |
call mintBatch |
METADATA_ROLE |
0x6bd6…2f80 |
create series and update, freeze or set metadata |
PAUSER_ROLE |
0x65d7…862a |
pause and unpause transfers |
ROYALTY_ROLE |
0xeb54…d98e |
set, clear or freeze the royalty |
ADMIN_ROLE (0xa498…1775) exists in the contract but was not granted at deployment and the deployer does not hold it. SeriesActivation holds no role: it only receives tokens. Whether any other account has been granted a role since deployment was not checked; hasRole(role, account) answers for any address.
SeriesActivation#
SeriesActivation at 0x412E962bbAE0bB97CE98e74f3424543651a21ce3 was deployed three blocks after the proxy, in block 30,569,436 (transaction), with two constructor arguments: the token contract, 0x4516a5D613C30A36D157d3b579813734cbb929a4, and _maxTimestampAge, 3600 seconds. Both are still the values it returns. It is also part of QRToken, written by Patryk Dwórznik, and an exact match of its verified source.
It is Ownable, not role-based: owner() returns the deployer, 0x73196fa74d6061e02648078246a1fE4D93a7AC2f, who can register holders and change maxTimestampAge. What it stores, per token id:
tokenHolders(id): the address registered as the token’s holder, the key the QR code carries. It is zero once the token is activated, and zero for an id that was never registered.activatedTokens(id):trueafter activation.tokenStatus(id):0for a registered token waiting for activation,1for an id with no registration,2for an activated token.
The contract only accepts tokens whose id has a registered holder: its onERC1155Received and onERC1155BatchReceived revert with UnregisteredTokenTransfer otherwise. That is why every series is registered first and minted second, as SmartMetal series shows for both. activate(timestamp, signature) is the one function anyone can call; Activate a SmartMetal describes it.
Check it yourself#
Each command is a JSON-RPC call to a public Base endpoint; swap in https://base-rpc.publicnode.com if the first one is busy.
# The proxy's implementation slot (EIP-1967): 0x…945d54b21a582d5d186ae1e449ddc2a4ce39e26c
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_getStorageAt","params":["0x4516a5d613c30a36d157d3b579813734cbb929a4","0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc","latest"]}'
# seriesCount(): 0x…02
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x4516a5d613c30a36d157d3b579813734cbb929a4","data":"0xd7f2c0ef"},"latest"]}'
# hasRole(MINTER_ROLE, 0x7319…AC2f): 0x…01, which is true
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x4516a5d613c30a36d157d3b579813734cbb929a4","data":"0x91d148549f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a600000000000000000000000073196fa74d6061e02648078246a1fe4d93a7ac2f"},"latest"]}'
# paused(): 0x…00, which is false
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x4516a5d613c30a36d157d3b579813734cbb929a4","data":"0x5c975abb"},"latest"]}'
# SeriesActivation: tokenContract() is 0x…4516a5d613c30a36d157d3b579813734cbb929a4, maxTimestampAge() is 0x…e10 (3600), owner() is 0x…73196fa74d6061e02648078246a1fe4d93a7ac2f
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x412e962bbae0bb97ce98e74f3424543651a21ce3","data":"0x55a373d6"},"latest"]}'
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x412e962bbae0bb97ce98e74f3424543651a21ce3","data":"0x0dee2789"},"latest"]}'
curl -s https://mainnet.base.org -X POST -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x412e962bbae0bb97ce98e74f3424543651a21ce3","data":"0x8da5cb5b"},"latest"]}'
With Foundry installed, its cast command runs the same checks and decodes the answers:
export ETH_RPC_URL=https://mainnet.base.org
# Implementation behind the proxy: 0x945d54b21a582d5d186ae1e449ddc2a4ce39e26c
cast implementation 0x4516a5d613c30a36d157d3b579813734cbb929a4
# 2
cast call 0x4516a5d613c30a36d157d3b579813734cbb929a4 'seriesCount()(uint256)'
# true
cast call 0x4516a5d613c30a36d157d3b579813734cbb929a4 'hasRole(bytes32,address)(bool)' $(cast keccak MINTER_ROLE) 0x73196fa74d6061e02648078246a1fE4D93a7AC2f
# false
cast call 0x4516a5d613c30a36d157d3b579813734cbb929a4 'paused()(bool)'
# 0x4516a5D613C30A36D157d3b579813734cbb929a4, 3600, 0x73196fa74d6061e02648078246a1fE4D93a7AC2f
cast call 0x412e962bbae0bb97ce98e74f3424543651a21ce3 'tokenContract()(address)'
cast call 0x412e962bbae0bb97ce98e74f3424543651a21ce3 'maxTimestampAge()(uint256)'
cast call 0x412e962bbae0bb97ce98e74f3424543651a21ce3 'owner()(address)'
The ABIs are served at /abi/smartmetal.json (the proxy), /abi/series1155v1.json and /abi/smartmetal-activation.json. To decode calls to the token, use the Series1155V1 ABI against the proxy address. The data files page lists every file.