Using 1inch ChiGas tokens to reduce transaction costs

What are gas tokens and example usage for Uniswap v2

Gas Prices Meme

Gas prices have been occasionally above 1000 Gwei in the past in peak times. Given an ETH price of over 1000 USD, this can lead to insane real transaction costs. In particular this can be a pain when using onchain DEX's like Uniswap, resulting in hundreds of dollars transaction fees for a single trade.

People have been using gas tokens to combat this issue. Let's explore what those are, how to use them and how you would integrate them to trade on Uniswap.

What are Gas Tokens?

Gas tokens are an Ethereum ERC-20 token that allows users to tokenize gas on the Ethereum network, storing gas when it is cheap and using / deploying this gas when it is expensive.

Using GasToken is particularly useful for scenarios of arbitraging decentralized exchanges or buying into ICOs early. They further allow users to buy and sell gas directly, enabling long-term "banking" of gas that can help shield users from rising gas prices.

The gas tokens work due to the refund mechanism of the Ethereum network. Whenever you release storage, Ethereum will refund you some gas for it, because you are reducing the size of the blockchain. Zero-ing a 32 bytes storage variable releases 15000 gas, while the setting to 0 operation costs 5000, effectively giving you a 3x gas return. Alternatively one can self-destruct a contract. This would cost 700 for the the call to the contract + 5000 for the selfdestruct operation, but refunds quite a bit more: 24000 gas.

And this is what gas tokens are using. You can mint them and they will store data in the contract. Then you can burn the tokens inside a transaction which will release gas. Refunds can only give up to half of the gas used by the transaction.

There are currently three versions available:

  1. GST1
  2. GST2
  3. Chi-Gas

GST1 is using the mechanism of storage variables which is more efficient when the gas prices between minting and burning is less than 3.71x different. In our current times of crazy gas fluctuations you are probably better off going with the other alternative. GST2 relies on the contract self-destruct mechanism, as well as the Chi-Gas.

What are Chi Gas Tokens?

Chi Gas added three ways to improve the efficiency of GST2:

  • Reducing the contract address size by mining a private key with Profanity address generator, which allowed to decrease size of the sub contracts by 1 byte.
  • Using CREATE2 instruction to deploy sub smart contracts for their efficient address discovery during burning process.
  • Fixing ERC20 incompatibilities of GST2.
Chi vs Gas Tokens

You can use the the Chi-Gas in your contracts using the modifier on the right. A short explanation of the constant values:

  • 21000 = initial cost of a transaction
  • 16 * msg.data.length = calldata cost (see EIP-2028)
  • gasStart - gasleft() = the actual gas used by your code
  • 14154 = freeFromUpTo costs
  • 41947 = refund per burnt gas token * 2 (times two due to max refund of half of all gas costs)

modifier discountCHI {
  uint256 gasStart = gasleft();

  _;

  uint256 initialGas = 21000 + 16 * msg.data.length;
  uint256 gasSpent = initialGas + gasStart - gasleft();
  uint256 freeUpValue = (gasSpent + 14154) / 41947;

  chi.freeFromUpTo(msg.sender, freeUpValue);
}

Now all you need to to do is add the ChiToken interface with the address:

interface ChiToken {
    function freeFromUpTo(address from, uint256 value) external;
}

ChiToken constant public chi = ChiToken(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c);

and your modifier will be working. When you want to use it, make sure to mint and approve Chi tokens to your contract beforehand. Oh and you can also deploy new contracts using Chi-gas using deployer.eth.

Example: Adding Chi tokens into UniSwap v2 integration

We will be building on top of my previous Uniswap v2 integration. As a reminder it is build on top for the Kovan test network using DAI. All we need to no is add the discountCHI modifier and add a new function with this modifier.

function convertEthToDaiWithGasRefund(uint daiAmount) external payable discountCHI {
    _convertEthToDai(daiAmount);
}

Congratulations, our Unicorn is now releasing its gas!

Unicorn releasing gas

Fully working Remix example

Here's a fully working example you can use directly on Remix, see below for instructions how to use it and a comparison.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.1;

import "https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol";

interface ChiToken {
    function freeFromUpTo(address from, uint256 value) external;
}

contract UniswapExample {
  ChiToken constant public chi = ChiToken(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c);
  IUniswapV2Router02 constant public uniRouter = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
  address constant public multiDaiKovan = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;

  modifier discountCHI {
    uint256 gasStart = gasleft();

    _;

    uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length;
    chi.freeFromUpTo(msg.sender, (gasSpent + 14154) / 41947);
  }
  
  function convertEthToDai(uint daiAmount) external payable {
    _convertEthToDai(daiAmount);
  }

  function convertEthToDaiWithGasRefund(uint daiAmount) external payable discountCHI {
    _convertEthToDai(daiAmount);
  }
  
  function getEstimatedETHforDAI(uint daiAmount) external view returns (uint256[] memory) {
    return uniRouter.getAmountsIn(daiAmount, _getPathForETHtoDAI());
  }

  function _getPathForETHtoDAI() private pure returns (address[] memory) {
    address[] memory path = new address[](2);
    path[0] = uniRouter.WETH();
    path[1] = multiDaiKovan;
    
    return path;
  }
  
  function _convertEthToDai(uint daiAmount) private {
    // using 'now' for convenience in Remix, for mainnet pass deadline from frontend!
    uint deadline = block.timestamp + 15;

    uniRouter.swapETHForExactTokens{ value: msg.value }(
      daiAmount,
      _getPathForETHtoDAI(),
      address(this),
      deadline
    );
    
    // refund leftover ETH to user
    (bool success,) = msg.sender.call{ value: address(this).balance }("");
    require(success, "refund failed");
  }
  
  // important to receive ETH
  receive() payable external {}
}

Uniswap Example Walkthrough

  1. First we have to mint some Chi-gas tokens. Switch MetaMask to Kovan and get some Test ETH. You can now mint Chi-gas tokens via Etherscan. Click mint and mint at least 4 tokens.
  2. Now have to deploy above contract to Kovan via Remix. Do this and copy the address.
  3. We can now approve at least 4 tokens to our contract again via Etherscan and approve.
  4. Now you can call the convertEthToDaiWithGasRefund function, but don't forget to pass enough Wei along in the top left in Remix. As a comparison we can call convertEthToDai to see the difference. Make sure to set a higher gas price to reflect mainnet.


Here's a comparison of my trade without and with using Chi-gas:

Regular Uniswap Trade
Uniswap Trade with ChiGas

Quite a bit saved assuming we minted the Chi-gas during periods of lower gas prices.

Gas tokens won't exist in the future

Vitalik just recently posted a new EIP-3298 which proposes to remove the refund mechanism. I let him explain it:

"

Gas refunds for SSTORE and SELFDESTRUCT were originally introduced to motivate application developers to write applications that practice “good state hygiene”, clearing storage slots and contracts that are no longer needed. However, they are not widely used for this, and poor state hygiene continues to be the norm. It is now widely accepted that the only solution to state growth is some form of statelessness or state expiry, and if such a solution is implemented, then disused storage slots and contracts would start to be ignored automatically.

Vitalik Buterin

He goes further on specifically about gas tokens which in his words have 'downsides to the network, particularly in exacerbating state size (as state slots are effectively used as a “battery” to save up gas) and inefficiently clogging blockchain gas usage'.

Keep in mind this is a very early EIP and won't come into effect any time soon. But it's on the horizon that gas tokens won't exist forever.


Markus Waas

Solidity Developer

More great blog posts from Markus Waas

  • Solidity Overview

    Solidity Fast Track 2: Continue Learning Solidity Fast

    Continuing to learn Solidity fast with the advanced basics

    Previously we learned all of the basics in 20 minutes . If you are a complete beginner, start there and then come back here. Now we'll explore some more advanced concepts, but again as fast as possible. 1. Saving money with events We all know gas prices are out of control right now, so it's more...

  • Berlin

    What's coming in the Berlin Hardfork?

    Looking at all the details of the upcoming fork

    The Berlin Hardfork is scheduled for April 14th after block 12,224,00. Later to be followed by the London Hardfork in July which will inculde EIP-1559 . So let's take a look at the new changes and what you need to know as a developer. EIP-2929: Increased gas costs for state access EIP-2929 will...

  • Zeppelin

    Openzeppelin Contracts v4 in Review

    Taking a look at the new Openzeppelin v4 Release

    The Openzeppelin v4 contracts are now available in Beta and most notably come with Solidity 0.8 support. For older compiler versions, you'll need to stick with the older contract versions. The beta tag means there still might be small breaking changes coming for the final v4 version, but you can...