It totally depends on how the transfer
function is implemented and what it does.
I ran some tests with a bare-bones ERC20 contract. Or, actually it doesn't anymore implement all needed functions but it implements the relevant functionality.
With the code given at the bottom of this post, Remix gives me a transaction cost for transfer at 51310 gas. Let's try to reduce this:
1) Send a second transfer to the same address. 36310 gas. This is cheaper as writing to an existing slot is cheaper (comments at https://ethereum.stackexchange.com/a/43902/31933)
2) Remove event emission from transfer
function and send second transfer to the same address: 34482 gas
3) Replace the SafeMath stuff with simpler +/- computations, 33805 gas
4) Remove all functionality from the function (except return true
): 23160 gas
As far as I can tell, the second step is about as reduced as we can get without compromising security.
Trickery
The previous examples include only tricks that can be done code-wise. If there is a token contract which has a secure and working transfer function, I'm guessing it works something like this:
1) The transfer
function includes only event emission and boolean return, no other functionality. Or strictly speaking even event emission could be removed.
2) A backend system monitors those events (or transactions)
3) The backend system stores the data in a regular database or so
4) Every X minutes the backend system issues a transaction to the token contract to update all the balances. So, basically the cost of token transfers is delegated to the backend system AND the token transfers are bundled together to save in transaction costs.
Used example code:
pragma solidity ^0.5.1;
contract ERC20Basic {
event Transfer(address indexed from, address indexed to, uint tokens);
mapping(address => uint256) balances;
uint256 totalSupply_;
using SafeMath for uint256;
constructor(uint256 total) public {
totalSupply_ = total;
balances[msg.sender] = totalSupply_;
}
function balanceOf(address tokenOwner) public view returns (uint) {
return balances[tokenOwner];
}
function transfer(address receiver, uint numTokens) public returns (bool) {
require(numTokens <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(numTokens);
balances[receiver] = balances[receiver].add(numTokens);
emit Transfer(msg.sender, receiver, numTokens);
return true;
}
}
library SafeMath {
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}