I was tinkering a bit with the following Vault contract. The contract works like that: Deposit Token X and receive minted shares. Withdraw Token X for the amount of shares you are holding and the shares get burned.

I want the shares to be a ERC20 Token(with a name, symbol etc.) but I am having the issue that once the shares are generated I cannot send them anywhere. Can anyone help me what I have to add?

Here is the affirmentioned code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Vault {
    IERC20 public immutable token;

    uint public totalSupply;
    string public symbol;
    string public name;
    uint8 public decimals;
    mapping(address => uint) public balanceOf;

    constructor(address _token) {
        token = IERC20(_token);
        name = "VaultWithdraw";
        symbol = "wdraw";
        decimals = 0;

    function _mint(address _to, uint _shares) private {
        totalSupply += _shares;
        balanceOf[_to] += _shares;

    function _burn(address _from, uint _shares) private {
        totalSupply -= _shares;
        balanceOf[_from] -= _shares;

    function deposit(uint _amount) external {
        a = amount
        B = balance of token before deposit
        T = total supply
        s = shares to mint

        (T + s) / T = (a + B) / B 

        s = aT / B
        uint shares;
        if (totalSupply == 0) {
            shares = _amount;
        } else {
            shares = (_amount * totalSupply) / token.balanceOf(address(this));

        _mint(msg.sender, shares);
        token.transferFrom(msg.sender, address(this), _amount);

    function withdraw(uint _shares) external {
        a = amount
        B = balance of token before withdraw
        T = total supply
        s = shares to burn

        (T - s) / T = (B - a) / B 

        a = sB / T
        uint amount = (_shares * token.balanceOf(address(this))) / totalSupply;
        _burn(msg.sender, _shares);
        token.transfer(msg.sender, amount);


interface IERC20 {
    function totalSupply() external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function transfer(address recipient, uint amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint amount);
    event Approval(address indexed owner, address indexed spender, uint amount);
  • "...but I am having the issue that once the shares are generated I cannot send them anywhere..". Can you clarify this phrase and your logic? When you use this statement 'token.transferFrom(msg.sender, address(this), _amount);' I think that's you're sending shares amount to who interact with this function... Commented Aug 12, 2022 at 15:13

1 Answer 1


To allow the transfer of shares your contract and make your contract fully ERC-20 compliant, you must implement the remaining logic of an ERC20 token (i.e. transfer, transferFrom, etc.)

An even better solution would be create a vault contract that is ERC4626 compliant. That would allow other devs to easily integrate your vault token in their application (example 1, example 2).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.