How does VERI differ from a modern ERC-20?

How VERI differs from a modern ERC-20

VERI is 2017 code whose initial allocation and ownership transfer emit no Transfer event, whose decimals() returns uint256, whose failed transfers throw instead of returning false, which has no zero-address checks, and whose transferOwnership moves the owner's whole balance to the new owner, as its one call on 24 Apr 2017 did with all 100,000,000 VERI.

Standard#
ERC-20
Symbol#
VERI
Decimals#
18
Transactions#
All transactions
Last verified#
13 Oct 2026

The VERI contract predates the final EIP-20 text and most of the conventions that grew around it. It works with every wallet and tool that calls balanceOf and transfer, but an indexer, a wrapper or a strict ABI decoder meets the differences below. Each one is read from the verified source.

Two balance changes emit no Transfer event#

Modern tokens emit Transfer(0x0, to, amount) when tokens are created, so that the sum of all Transfer logs equals every balance. VERI changes balances twice without a log:

  1. The initial allocation. The constructor writes balances[msg.sender] = totalSupply directly. The creation transaction has no logs, so 100,000,000 VERI appeared with no Transfer.
  2. transferOwnership. It copies the owner’s balance to the new owner and zeroes the old one, with no event. The one call on record moved all 100,000,000 VERI with no Transfer.

An indexer that rebuilds balances from Transfer logs therefore puts the whole supply nowhere, and every later balance it computes for the first holders is off. Read balanceOf instead, as in Check a VERI balance.

decimals() returns uint256#

uint public decimals = 18;

EIP-20 specifies decimals() as uint8. VERI declares it as uint, so the ABI and the return word are uint256. The value is 18, and a decoder that reads the low byte of the 32-byte word gets the same answer. A strictly typed client that expects uint8 in the ABI needs the committed ABI, which says uint256.

Failures throw; successes return true#

transfer, transferFrom and approve all return true. VERI does not have the “missing return value” problem of some tokens from the same year. But they never return false: an insufficient balance or allowance reaches SafeMath.safeSub, whose custom assert calls throw:

function safeSub(uint a, uint b) internal returns (uint) {
  assert(b <= a);
  return a - b;
}

function assert(bool assertion) internal {
  if (!assertion) {
    throw;
  }
}

throw in Solidity 0.4.8 compiles to an invalid opcode, which reverts the state and consumes all the gas sent with the transaction. A wrapper that checks the return value for failure never sees one; it has to treat a revert as the failure.

No zero-address checks#

transfer and transferFrom accept any _to, including 0x0. Tokens sent there are not burned: they sit in balances[0x0], still count in totalSupply, and show up when you call balanceOf for the zero address (the command in VERI supply is fixed at 100,000,000 reads it).

approve overwrites, with no increase or decrease#

function approve(address _spender, uint _value) returns (bool success) {
  allowed[msg.sender][_spender] = _value;
  Approval(msg.sender, _spender, _value);
  return true;
}

approve sets the allowance to _value whatever it was before, which is the approve/transferFrom race described in EIP-20. There is no increaseAllowance, decreaseAllowance or permit. The safe pattern is to set the allowance to zero before setting a new value.

transferOwnership moves the owner’s whole balance#

In most contracts, transferOwnership changes an address and nothing else. In VERI it also moves tokens.

The code#

VeritaseumToken overrides the transferOwnership it inherits from Ownable (verified source):

// VeritaseumToken
function transferOwnership(address _newOwner) onlyOwner {
    balances[_newOwner] = balances[owner];
    balances[owner] = 0;
    Ownable.transferOwnership(_newOwner);
}

// Ownable
function transferOwnership(address newOwner) onlyOwner {
    if (newOwner != address(0)) {
        owner = newOwner;
    }
}

What one call does#

Only the current owner can call it (onlyOwner throws for anyone else). A successful call does three things, in this order:

  1. Overwrites the new owner’s balance with the owner’s balance. It is an assignment, not an addition. Whatever _newOwner held before is gone.
  2. Sets the old owner’s balance to zero.
  3. Changes owner, but only if _newOwner is not the zero address.

Three things it does not do:

  • It emits no event. There is no Transfer for the moved balance and no OwnershipTransferred. A balance rebuilt from Transfer logs misses this move entirely (see above).
  • It does not change totalSupply, even when step 1 destroys tokens. The supply stays at 100,000,000.
  • It does not move allowances. Anything the old owner approved stays in allowed[oldOwner][spender], attached to an address whose balance is now zero.

Ownership carries exactly one power: calling this function again. The owner cannot mint, burn, pause or touch anyone else’s balance or allowance.

Edge cases#

These follow from the code; none has happened on chain.

_newOwner is Result
an address that already holds VERI its balance is replaced by the owner’s; the VERI it held is destroyed and totalSupply is unchanged
the owner itself step 1 is a no-op and step 2 zeroes the owner: the owner’s whole balance is destroyed
the zero address the balance moves to 0x0, the owner is zeroed, and owner stays as it was: the tokens are lost

The one call on record#

The deployer, 0x44CAb6F6DC7045FD4AcD1d0f3d09Fc7a83004bd3, called transferOwnership(0x82c48875C17EE5812f909a9d75C0F64f7A8719FE) in block 3,589,599 on 24 Apr 2017 at 01:37:44 UTC, the day after deployment (transaction). It used 40,088 gas and emitted no log.

Read from an archive node, the balances around that block are:

Address Block 3,589,598 Block 3,589,599
0x44CAb6F6DC7045FD4AcD1d0f3d09Fc7a83004bd3 (deployer) 100,000,000 VERI 0
0x82c48875C17EE5812f909a9d75C0F64f7A8719FE (new owner) 0 100,000,000 VERI

So the call moved the full supply. owner() has returned 0x82c48875C17EE5812f909a9d75C0F64f7A8719FE ever since; the address is an externally owned account. Every transaction sent to the contract was checked on 13 Oct 2026 for the transferOwnership selector 0xf2fde38b. This is the only successful call. One other attempt, from an address that was not the owner, threw in onlyOwner on 26 Dec 2017 and changed nothing. Since the owner has always been an externally owned account, no contract could have called the function on its behalf.

What else is missing#

  • totalSupply is declared twice (in the abstract ERC20 and again in VeritaseumToken); the getter returns the initialised one, 10^26. See VERI supply is fixed at 100,000,000.
  • No ERC-165 supportsInterface, no transfer hooks, no pause, no mint and no burn.
  • No delegatecall and no proxy, so none of the above can be fixed in place.

Check it yourself#

The commands are eth_call and eth_getTransactionReceipt requests to public Ethereum JSON-RPC endpoints.

# decimals(): a full 32-byte word, 0x0000…0012
curl -s https://ethereum-rpc.publicnode.com -X POST -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374","data":"0x313ce567"},"latest"]}'

# The creation receipt: "logs": [], so the 100,000,000 VERI allocation emitted no Transfer
curl -s https://eth.drpc.org -X POST -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionReceipt","params":["0xfda7aad54c81d9bc8e7a67e68821a24009c2bcd5e9b9a47b71f40d5a45f3a6fc"]}'

# The transferOwnership receipt: "logs": [] again, and "gasUsed": "0x9c98" (40,088)
curl -s https://eth.drpc.org -X POST -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionReceipt","params":["0x5d7d007e7dbf534a2983880be117100691cf351fdc45d6adb2249c6fd3a8d4b1"]}'

# owner(): 0x…82c48875c17ee5812f909a9d75c0f64f7a8719fe
curl -s https://ethereum-rpc.publicnode.com -X POST -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374","data":"0x8da5cb5b"},"latest"]}'

The balances before and after the call need an archive node. https://eth.drpc.org serves historical eth_call without a key: pass "0x36c5de" (3,589,598) or "0x36c5df" (3,589,599) instead of "latest", with balanceOf calldata as in Check a VERI balance.

With Foundry installed, its cast command runs the same calls and decodes the answers:

export ETH_RPC_URL=https://eth.drpc.org

# 18; the ABI says uint256, so that is the return type to decode with
cast call 0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374 'decimals()(uint256)'

# Both receipts print logs []
cast receipt 0xfda7aad54c81d9bc8e7a67e68821a24009c2bcd5e9b9a47b71f40d5a45f3a6fc logs
cast receipt 0x5d7d007e7dbf534a2983880be117100691cf351fdc45d6adb2249c6fd3a8d4b1 logs

# 0x82c48875C17EE5812f909a9d75C0F64f7A8719FE
cast call 0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374 'owner()(address)'

# The transferOwnership input, decoded: "transferOwnership(address)" 0x82c48875C17EE5812f909a9d75C0F64f7A8719FE
cast tx 0x5d7d007e7dbf534a2983880be117100691cf351fdc45d6adb2249c6fd3a8d4b1 input | xargs cast 4byte-decode

# The deployer before and after: 100000000000000000000000000 [1e26], then 0
cast call 0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374 'balanceOf(address)(uint256)' 0x44CAb6F6DC7045FD4AcD1d0f3d09Fc7a83004bd3 --block 3589598
cast call 0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374 'balanceOf(address)(uint256)' 0x44CAb6F6DC7045FD4AcD1d0f3d09Fc7a83004bd3 --block 3589599

# The new owner before and after: 0, then 100000000000000000000000000 [1e26]
cast call 0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374 'balanceOf(address)(uint256)' 0x82c48875C17EE5812f909a9d75C0F64f7A8719FE --block 3589598
cast call 0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374 'balanceOf(address)(uint256)' 0x82c48875C17EE5812f909a9d75C0F64f7A8719FE --block 3589599

Sources#

  1. VERI verified source, Etherscan
  2. VERI contract creation transaction, Etherscan
  3. The transferOwnership transaction of 24 Apr 2017, Etherscan
  4. The transferOwnership transaction of 24 Apr 2017, Blockscout
  5. EIP-20: Token Standard